前面提到单例模式在多线程环境下并非“单例”:https://blog.csdn.net/Lunar_Queen/article/details/81776647。
下面提出了一种解决该问题的方法:类的静态数据成员只会被初始化一次。
示例代码如下:
#include<iostream>
#include<Windows.h>
#include<process.h>
using namespace std;
//单例模式
//构造函数私有化
//提供一个全局的静态变量方法
//在类中定义一个全局的指针
class Singleton
{
private:
Singleton()//构造函数私有化
{
m_Count++;
printf("Singleton Begin!!!\n");//使用printf()函数比较好
Sleep(1000);
printf("Singleton End!!!\n");
}
public:
static Singleton* GetSingelton()//提供一个全局的访问点
{
/*
//此写法不能保证单例,必须加上判断
return new Singleton();
*/
/*
if(single==NULL)
{//每一次都需要判断该单例是否存在?
single=new Singleton();//有可能导致多个线程调用词语局,导致非单例
}*/
return single;//直接返回
}
static void Print()
{
printf("Calling Count=%d\n",m_Count);
}
private:
static Singleton* single;
static int m_Count;//增加一个计数器,标识构造函数被调用的次数
};
Singleton* Singleton::single=new Singleton();//在类外对类中的数据成员进行初始化
int Singleton::m_Count=0;
/*
int main()
{
//目的:不希望客户调用构造函数;不希望客户构造两个同类型的对象,防止资源浪费。
//Singleton* p1=new Singleton;//出错,构造函数已经私有化。
//Singleton* p2=new Singleton;
Singleton* p1=Singleton::GetSingelton();
Singleton* p2=Singleton::GetSingelton();
if(p1==p2)
{
cout<<"p1==p2"<<endl;
}
else
{
cout<<"p1!=p2"<<endl;
}
return 0;
}
*/
//分析
//此模式为典型的懒汉模式,因为呐。只有在GetSingelton()这个函数被调用时,
//才会new一个单例。
//缺点:new时才会调用构造函数,C++的构造函数不是线程安全的。
//线程安全性演示
//懒汉式--遇到多线程问题--原因呢?判断语句根本不起作用。
void MyThreadFunc (void *p)
{
printf("ThreadID=%d\n",GetCurrentThreadId());
Singleton *single=Singleton::GetSingelton();
Singleton::Print();
return;
}
int main()
{
int ThreadNum=3;
HANDLE HThread[3];
for(int i=0;i<ThreadNum;++i)
{
HThread[i]=(HANDLE)_beginthread(MyThreadFunc,0,NULL);//返回线程句柄,可以操作线程--挂起、暂停
}
for(int i=0;i<ThreadNum;++i)
{//让主线程等待所有的子线程运行完毕,或者说让操作系统挂起主线程。
WaitForSingleObject(HThread[i],INFINITE );
}
printf("main() endling\n");
return 0;
}
//分析--一次调用两次返回。
//主进程消失,子进程不一定消失。孤儿进程。
//主线程消失,子线程也消失。
//饿汉式单例模式--可保证构造函数仅被调用一次。
//在静态成员指针变量初始化时给其赋予初值。
执行上述程序,运行结果如下图所示:
可以看到,仅产生了类的一个实例。