02C++单例模式线程安全问题

本文探讨了单例模式在多线程环境下的实现问题,对比了懒汉式和饿汉式的优缺点,并介绍了双重检查加锁机制来确保线程安全。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.下面的的单例代码在多线程情况下可能产生多个实例

#include <iostream>
#include <string>
#include <vector>
#include <list>

#include "windows.h"
#include "process.h"

using namespace std;

// 单例模式的多线程问题。
// 懒汉存在线程安全问题,饿汉不存在线程安全问题,但是造成资源浪费。

// 懒汉式
// 1"懒汉"模式虽然有优点,但是每次调用GetInstance()静态方法时,必须判断
// NULL == m_instance,使程序相对开销增大。
// 2.多线程中会导致多个实例的产生,从而导致运行代码不正确以及内存的泄露。
// 3.提供释放资源的函数

// 4.C++的构造函数是线程不安全的。
// C++中的构造函数简单来说分两步:
// 第一步:内存分配
// 第二步:初始化成员变量

class Singleton3 {
public:
  static Singleton3* GetInstance() {
    if (singleton_ == NULL) {
      Sleep(1000);
      singleton_ = new Singleton3;
    }
    return singleton_;
  }

  static int count() { return count_; }

  static void DestreyInstance() {
    if (singleton_ != NULL) {
      delete singleton_;
    }
  }

private:
  // 防止外部构造。
  Singleton3() {
    count_++;
  }

  // 防止拷贝和赋值。
  Singleton3& operator=(const Singleton3&);
  Singleton3(const Singleton3& singleton3) {}

private:
  static Singleton3* singleton_;
  static int count_;
};

Singleton3* Singleton3::singleton_ = NULL;
int Singleton3::count_ = 0;

void PrintSingleton3(void*) {
  cout << Singleton3::GetInstance()->count() << endl;
}

//-------------------------------------------------------
// 饿汉式
class Singleton4 {
public:
  static Singleton4* GetInstance() {
    return singleton_;
  }

  static int count() { return count_; }

  static void DestreyInstance() {
    if (singleton_ != NULL) {
      delete singleton_;
    }
  }

private:
  // 防止外部构造。
  Singleton4() {
    Sleep(1000);
    count_++;
  }

  // 防止拷贝和赋值。
  Singleton4& operator=(const Singleton4&);
  Singleton4(const Singleton4& singleton4) {}

private:
  static Singleton4* singleton_;
  static int count_;
};

Singleton4* Singleton4::singleton_ = new Singleton4;
int Singleton4::count_ = 0;

void PrintSingleton4(void*) {
  cout << Singleton4::GetInstance()->count() << endl;
}

int main09() {
  HANDLE thread[10];
  for (int i = 0; i < 3; i++) {
    thread[i] = (HANDLE)_beginthread(PrintSingleton3, 0, NULL);
  }

  for (int i = 0; i < 3; i++) {
    WaitForSingleObject(thread[i], INFINITE);
  }

  for (int i = 0; i < 3; i++) {
    thread[i] = (HANDLE)_beginthread(PrintSingleton4, 0, NULL);
  }

  for (int i = 0; i < 3; i++) {
    WaitForSingleObject(thread[i], INFINITE);
  }

  Singleton4::DestreyInstance();
  Singleton3::DestreyInstance();

  return 0;
}

2.双重检查加锁机制解决懒汉模式的多线程问题。

#include <iostream>
#include <string>
#include <vector>
#include <list>

#include "windows.h"
#include "process.h"

using namespace std;

// 双重检查加锁机制解决懒汉模式的多线程问题。
// 两次检查的作用,内部检查是在instance还没new出来时,两个线程都通过了外部检查,都到了lock位置处,然后
// 其中一个线程进入内部检查后new出了instance,此时内部检查防止第二个线程继续new出instance。
// instance已经new出来以后,如果没有外层判断,GetInstance时每次都要进行lock,费时操作,所以在外层又套了一个判断,
// 防止进入lock。

class Locker {
public:
  Locker() { m_hMutex = CreateMutex(NULL, FALSE, NULL); }
  ~Locker() { CloseHandle(m_hMutex); }
  void lock() { WaitForSingleObject(m_hMutex, INFINITE); }
  void unlock() { ReleaseMutex(m_hMutex); }

private:
  HANDLE m_hMutex;
};

class Singleton5 {
public:
  static Singleton5* GetInstance() {
    if (singleton_ == NULL) {
      locker_.lock();
      if (singleton_ == NULL) {
        singleton_ = new Singleton5;
      }
      locker_.unlock();
    }
    return singleton_;
  }

  static int count() { return count_; }

  static void DestreyInstance() {
    if (singleton_ != NULL) {
      delete singleton_;
    }
  }

private:
  // 防止外部构造。
  Singleton5() {
    Sleep(1000);
    count_++;
  }

  // 防止拷贝和赋值。
  Singleton5& operator=(const Singleton5&);
  Singleton5(const Singleton5& singleton5) {}

private:
  static Singleton5* singleton_;
  static int count_;
  static Locker locker_;
};

Singleton5* Singleton5::singleton_ = NULL;
Locker Singleton5::locker_;
int Singleton5::count_ = 0;

void PrintSingleton5(void*) {
  cout << Singleton5::GetInstance()->count() << endl;
}

int main10() {
  HANDLE thread[10];
  for (int i = 0; i < 3; i++) {
    thread[i] = (HANDLE)_beginthread(PrintSingleton5, 0, NULL);
  }

  for (int i = 0; i < 3; i++) {
    WaitForSingleObject(thread[i], INFINITE);
  }

  Singleton5::DestreyInstance();
  return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值