为什么说懒汉式遇上多线程会出现问题?
比如我们在Singleton的构造函数中加上sleep(1000),当第一个线程到来时判断为NULL,去创建,并中间挂起;当第二个线程到来时,仍旧判断为NULL,依次类推,这就不是单个实例了。(也就是说,创建单例如果需要一定时间,这时在多线程情况下会出现“竞速创建”!(可能还有别的原因))
新建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