单例懒汉式和多线程问题
作为单例模式,是在整个程序运行期间只会建立一份内存空间,为了达到这个目标
1、需要将构造函数设置为私有成员
2、需要一个私有的静态指针指向自身
3、需要一个公有的静态函数将这个上面的静态指针露出来
如下的代码就是一个懒汉式的单例
但是上面的代码有明显的问题,就是遇到多线程的情况下,因为多个线程如果同事创建内存,由于彼此之间
并不能及时检查到内存已经分配,会分配多个内存,这个时候我们至少需要一个线程间同步手段来让他们之间
串行的执行,这个时候就涉及到两次检查(double check)
如果没有mutex保护就是下面这个程序:
会跑出结果
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
现在就是正常的了。所以懒汉试单例遇到多线程一定要注意,饿汉试没有问题。
当然这是一个小列子而已,线程安全是一个很大的话题,特别需要注意。
作者微信:
作为单例模式,是在整个程序运行期间只会建立一份内存空间,为了达到这个目标
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 }
这样代码如下:
点击(此处)折叠或打开
- #include <iostream>
- #include <unistd.h>
- using namespace std;
-
- pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;
-
- //单列模式
- 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)
- {
- pthread_mutex_lock(&counter_mutex); //mutex 保护临界区
- if(myc == NULL) //两次检查
- {
- myc = new single_ins;
- cnt++;
- }
- pthread_mutex_unlock(&counter_mutex); //mutex结束
- }
- //懒汉式
- 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 end
a:10a:10
b:20
1
0x7f21f40008c0
b:20
1
0x7f21f40008c0
a:10
b:20
1
0x7f21f40008c0
现在就是正常的了。所以懒汉试单例遇到多线程一定要注意,饿汉试没有问题。
当然这是一个小列子而已,线程安全是一个很大的话题,特别需要注意。
作者微信: