单例懒汉式和多线程问题
作为单例模式,是在整个程序运行期间只会建立一份内存空间,为了达到这个目标
1、需要将构造函数设置为私有成员
2、需要一个私有的静态指针指向自身
3、需要一个公有的静态函数将这个上面的静态指针露出来
如下的代码就是一个懒汉式的单例
-
#include<iostream>
-
using namespace std;
-
-
class single_ins
-
{
-
private:
-
int a;
-
int b;
-
single_ins()
-
{
-
a= 0;
-
b= 0;
-
}
-
static single_ins* myc;
-
public:
-
void setval(const int& a,const int& b)
-
{
-
this->a = a;
-
this->b = b;
-
}
-
-
void print()
-
{
-
cout<<"a:"<<a<<endl;
-
cout<<"b:"<<b<<endl;
-
}
-
-
-
static single_ins* setp()
-
{
-
//?
-
if(myc == NULL)
-
{
-
myc = new single_ins;
-
}
-
//?
-
return myc;
-
}
-
-
static void pfree()
-
{
-
if(myc != NULL)
-
{
-
delete myc;
-
myc = NULL;
-
}
-
}
-
-
};
-
-
//? init static value
-
single_ins* single_ins::myc = NULL;
-
//nit static value
-
//single_ins* single_ins::myc = new single_ins;
-
-
int main()
-
{
-
single_ins* a = single_ins::setp();
-
single_ins* b = single_ins::setp();
-
a->setval(10,20);
-
b->print();
-
-
cout<<a<<" "<<b<<endl;
-
single_ins::pfree();
-
-
}
但是上面的代码有明显的问题,就是遇到多线程的情况下,因为多个线程如果同事创建内存,由于彼此之间
并不能及时检查到内存已经分配,会分配多个内存,这个时候我们至少需要一个线程间同步手段来让他们之间
串行的执行,这个时候就涉及到两次检查(double check)
如果没有mutex保护就是下面这个程序:
-
#include <iostream>
-
#include <unistd.h>
-
using namespace std;
-
-
-
//单列模式
-
class single_ins
-
{
-
private:
-
int a;
-
int b;
-
single_ins()
-
{
-
cout<<"con begin/n";
-
a= 0;
-
b= 0;
-
sleep(10); //故意拖长构造函数执行时间,造成懒汉式多线程问题
-
cout<<"con end/n";
-
}
-
static single_ins* myc;//单例需要一个静态指针
-
static int cnt;//构造调用次数统计
-
public:
-
void setval(const int& a,const int& b)
-
{
-
this->a = a;
-
this->b = b;
-
}
-
-
void print()
-
{
-
cout<<"a:"<<a<<endl;
-
cout<<"b:"<<b<<endl;
-
cout<<cnt<<endl;
-
}
-
-
-
static single_ins* setp() //函数获得指针值赋给静态成员指针变量
-
{
-
//懒汉式
-
if(myc == NULL)
-
{
-
myc = new single_ins;
-
cnt++;
-
}
-
//懒汉式
-
return myc;
-
}
-
static void pfree()
-
{
-
if(myc != NULL)
-
{
-
delete myc;
-
myc = NULL;
-
}
-
}
-
};
-
-
//懒汉式 init static value
-
single_ins* single_ins::myc = NULL;
-
int single_ins::cnt = 0;
-
//饿汉试 init static value
-
//single_ins* single_ins::myc = new single_ins;
-
/*
-
懒汉式的问题在于多线程调用的时候会出现问题,很可能同时建立出多个内存空间,
-
而不是单列了。
-
*/
-
void* main21(void* argc)
-
{
-
single_ins* inp = (single_ins*)argc;
-
-
inp = single_ins::setp();
-
inp->setval(10,20);
-
inp->print();
-
cout<<inp<<"/n";
-
return NULL;
-
}
-
-
-
int main(void)
-
{
-
pthread_t tid;
-
single_ins* a[3] = {NULL};
-
void* tret[3] = {NULL};
-
for(int i = 0 ; i<3; i++)
-
{
-
pthread_create(&tid,NULL,main21,(void*)a[i]);
-
//pthread_join(tid, &(tret[i]));
-
}
-
sleep(50);
-
single_ins::pfree();
-
-
}
会跑出结果
con begin
con begin
con begin
con end
a:10
b:20
1
0x7fc3880008c0
con end
a:10
b:20
2
0x7fc3800008c0
con end
a:10
b:20
3
0x7fc3840008c0
可以看到
0x7fc3880008c0 0x7fc3800008c0 0x7fc3840008c0
明显是3个不同的内存空间 这就不对了,而且可以看到构造函数
调用了3次
为此我们使用mutex来保护临时
如下:
static single_ins* setp() //函数获得指针值赋给静态成员指针变量
39 {
40 //懒汉式
41 if(myc == NULL)
42 {
43 pthread_mutex_lock(&counter_mutex); //mutex 保护临界区
44 if(myc == NULL) //两次检查
45 {
46 myc = new single_ins;
47 cnt++;
48 }
49 pthread_mutex_unlock(&counter_mutex); //mutex结束
50 }
这样代码如下:
跑出的结果如下:
con begin
con end
a:10a:10
b:20
1
0x7f21f40008c0
b:20
1
0x7f21f40008c0
a:10
b:20
1
0x7f21f40008c0
现在就是正常的了。所以懒汉试单例遇到多线程一定要注意,饿汉试没有问题。
当然这是一个小列子而已,线程安全是一个很大的话题,特别需要注意。