直接看代码:
/* 单例模式可以保证:在一个程序当中,一个类有且只有一个实例,并提供一个访问 它的全局访问点 在程序设计当中,很多情况下需要确保一个类只有一个实例 例如: windopws系统中只能有一个窗口管理器 某个程序中只能有一个日志输出系统 一个GUI系统类库中,有且只有一个ImageManager */ #include <iostream> #include <windows.h> #include <process.h> using namespace std; //Meyers Singleton Pattern实现 class CSingleton2 { public: //单例对象使用局部静态变量方式从而使之延迟到调用的时候实例化 static CSingleton2& GetInstance() { static CSingleton2 sg; return sg; } void Print() { printf("print Singleton2 count = %d\n",m_count); } private: int m_count; //构造函数私有化,让外部不能访问,达到只能有一个实例对象的效果 CSingleton2() { printf("开始 construct Singleton2 count = %d\n",m_count); ::Sleep(1000);//这里是为了看到效果 m_count = 100; printf("结束 construct Singleton2 count = %d\n",m_count); } public: ~CSingleton2() { printf("调用析构函数\n"); } private: //防止拷贝构造和赋值操作 CSingleton2(const CSingleton2&); CSingleton2& operator=(const CSingleton2&); }; unsigned int __stdcall thread(void*) { printf("current Thread ID = %d\n", ::GetCurrentThreadId()); CSingleton2::GetInstance().Print(); return 0; } void TestMultThread() { //这里创建三个线程 for(int i = 0; i < 3; i++) { HANDLE t = (HANDLE)::_beginthreadex(NULL,0,thread,NULL,0,NULL); ::CloseHandle((HANDLE)t); } } int main() { TestMultThread(); getchar(); return 0; } /* 1:优点: 1):该实现是一个“懒汉”单例模式,意味着只有在第一次调用GetInstance()的时候才会实例化 2):不需要每次调用GetInstance()静态方法时,必须判断NULL==m_instance,效率相对高一点 3):使用对象而不是指针分配内存,因此自动调用析构函数,不会导致内存泄露 4):在多线程下的确能够保证有且只有一个实例产生。 2:缺点: 在多线程情况下,并不是真正的线程安全 */ /* current Thread ID = 1148 开始 construct Singleton2 count = 0 --- 假设1148线程创建单件实例,分配内存,但是还未初始化实例的成员变量 current Thread ID = 6668 print Singleton2 count = 0 current Thread ID = 6892 print Singleton2 count = 0 -- 线程6668拿到所有权,此时Singleton2内存已经分配好了,但是成员变量还没初始化,所以调用Print,m_count = 0; 结束 construct Singleton2 count = 100 -- 6892拿到线程所有权,继续进行成员变量的初始化,然后调用Print函数,输出100; print Singleton2 count = 100 调用析构函数 -- 一次析构函数,说明生成了一个实例对象 Press any key to continue 原因: 这是因为C++构造函数并不是线程安全的。 C++中的构造函数简单来说分两步: 第一步:内存分配 第二步:初始化成员变量 由于多线程的关系,可能当我们在分配内存好了以后,还没来得急初始化成员变量,就 进行线程切换,另外一个线程拿到所有权后,由于内存已经分配好了,但是变量初始化 还没进行,因此打印成员变量的相关值会发生不一致现象。 结论:Meyers 方式虽然能确保在多线程中产生唯一的实例,但是不能确保成员变量的值是否正确。 */
时间: 2024-10-10 10:02:32