懒汉式单例模式的多线程问题
2015-10-08 09:56
267 查看
为什么说懒汉式遇上多线程会出现问题?
比如我们在Singleton的构造函数中加上sleep(1000),当第一个线程到来时判断为NULL,去创建,并中间挂起;当第二个线程到来时,仍旧判断为NULL,依次类推,这就不是单个实例了。(也就是说,创建单例如果需要一定时间,这时在多线程情况下会出现“竞速创建”!(可能还有别的原因))
从上例的运行结果看,Singelton()的构造函数执行了三次,不再是单例!
![](https://img-blog.csdn.net/20160910162657354)
小插曲:——endl和"\n"的区别:
在MyThreadFunc()函数中,cout << "我是线程体 ...." << endl; //cout << endl; 等价于: cout << '\n' << flush;endl刷新缓冲区;。而cout << "我是线程体 ....\n";在C++里\n不刷新缓冲区。
懒汉式多线程同步:(优化上述代码)——使用临界区
新建MFC程序测试:
点击按钮,可以看到Singleton()构造函数只执行了一次,m_count的输出值自然也就均为1.
附:http://blog.csdn.net/hackbuteer1/article/details/7460019
比如我们在Singleton的构造函数中加上sleep(1000),当第一个线程到来时判断为NULL,去创建,并中间挂起;当第二个线程到来时,仍旧判断为NULL,依次类推,这就不是单个实例了。(也就是说,创建单例如果需要一定时间,这时在多线程情况下会出现“竞速创建”!(可能还有别的原因))
#include<iostream> #include"windows.h" #include"winbase.h" #include<process.h> using namespace std; class SingletonBug { private: static SingletonBug* m_pBug; SingletonBug() { cout << "constructor Begin()" << endl; Sleep(3000); cout << "constructor end()" << endl; } public: static SingletonBug* getInstance() { if (m_pBug == NULL) { m_pBug = new SingletonBug; } return m_pBug; } static void freeInstance() { if (m_pBug != NULL) { delete m_pBug; m_pBug = NULL; } } static void print() { cout << "I am Singleton" << endl; } }; SingletonBug* SingletonBug::m_pBug = NULL; //void main011() //单线程 //{ // SingletonBug* p1 = SingletonBug::getInstance(); // SingletonBug* p2 = SingletonBug::getInstance(); // // if (p1 == p2) // cout << "only" << endl; // else // cout << "double" << endl; // // SingletonBug::freeInstance(); //} void myThreadPro(void *) { cout << "线程体执行" << endl; SingletonBug::getInstance()->print(); } int main() //多线程 { HANDLE hThread[10]; for (int i = 0; i < 3; i++) { hThread[i] = (HANDLE)_beginthread(myThreadPro, 0, NULL); } for (int i = 0; i < 3; i++) { WaitForSingleObject(hThread[i], INFINITE); } return 0; }
从上例的运行结果看,Singelton()的构造函数执行了三次,不再是单例!
小插曲:——endl和"\n"的区别:
在MyThreadFunc()函数中,cout << "我是线程体 ...." << endl; //cout << endl; 等价于: cout << '\n' << flush;endl刷新缓冲区;。而cout << "我是线程体 ....\n";在C++里\n不刷新缓冲区。
void main() { int n = 10; cout << n << '\n'; //operator <<(ostream&, char) cout << n << "\n"; //operator <<(ostream&, const char *) cout << n << endl; /* inline ostream &std::endl(ostream& OutStream) { OutStream.put('\n'); OutStream.flush(); return OutStream; } */ }<<并不是后面跟着什么就直接输出到屏幕什么!cout代表后面的内容输出到 控制台的一个缓冲槽 ,而不是控制台(黑屏幕)。那么缓冲槽在什么情况下会把缓冲槽的内容输出到控制台的“黑屏幕界面”??当遇到endl或者其他fflush之类的命令或函数时,缓冲槽里的内容会按照顺序输出到控制台,再由控制台进行 转义字符 的识别打印。endl会换行、清槽——把缓冲槽里的内容输出到控制台。
懒汉式多线程同步:(优化上述代码)——使用临界区
新建MFC程序测试:
//临界区 static CCriticalSection cs; class Singleton { private: Singleton() { m_count ++; TRACE("Singleton begin\n"); Sleep(1000); TRACE("Singleton end\n"); } Singleton(const Singleton &); Singleton& operator = (const Singleton &); public: static void printV() { TRACE("printV..m_count:%d \n", m_count); } static Singleton *Instantialize() { if(pInstance == NULL) //第一次检查 { // 之所以在对pInstance 是否为空做了两次判断,是因为该方法调用一次就产生了对象,pInstance == NULL 大部分情况下都为false, // 如果每次获取实例就加锁,效率太低。而改进的方法只需要在第一次——调用的时候加锁,可大大提高效率。 cs.Lock(); //只有当pInstance等于null时,才开始使用加锁机制 二次检查 if(pInstance == NULL) //第二次检查 { pInstance = new Singleton(); } cs.Unlock(); } return pInstance; } static Singleton *pInstance; static int m_count; }; Singleton* Singleton::pInstance = NULL; //懒汉式 int Singleton::m_count = 0; ////////////////////////////////////////////////////////////////////////// void threadfunc(void *myIpAdd) { Singleton::Instantialize()->printV(); } void C懒汉式线程同步Dlg::OnBnClickedButton1() //主线程 { int i = 0; DWORD dwThreadId[201], dwThrdParam = 1; HANDLE hThread[201]; int threadnum = 3; for (i=0; i<threadnum; i++) //子线程 { hThread[i] = (HANDLE)_beginthread(&threadfunc, 0 , 0 ); if (hThread[i] == NULL) { TRACE("begin thread %d error!!!\n", i); break; } } for (i=0; i<threadnum; i++) { WaitForSingleObject( hThread[i], INFINITE ); } }
点击按钮,可以看到Singleton()构造函数只执行了一次,m_count的输出值自然也就均为1.
附:http://blog.csdn.net/hackbuteer1/article/details/7460019
相关文章推荐
- Python3写爬虫(四)多线程实现数据爬取
- PropertyChangeListener简单理解
- 什么是设计模式
- 设计模式之创建型模式 - 特别的变量问题
- 七、设计模式——装饰模式
- 设计模式总结
- 设计模式之创建型模式
- 浅谈设计模式的学习
- C#实现多线程的同步方法实例分析
- 浅谈chuck-lua中的多线程
- C#简单多线程同步和优先权用法实例
- C#多线程学习之(四)使用线程池进行多线程的自动管理
- C#多线程编程中的锁系统(三)
- C#多线程学习之(六)互斥对象用法实例
- 基于一个应用程序多线程误用的分析详解
- C#多线程学习之(三)生产者和消费者用法分析
- C#多线程学习之(一)多线程的相关概念分析
- C#多线程之Thread中Thread.IsAlive属性用法分析
- C#控制台下测试多线程的方法
- Ruby 多线程的潜力和弱点分析