單例懶漢式和多線程問題
作為單例模式,是在整個程式運作期間隻會建立一份記憶體空間,為了達到這個目标
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>
//單列模式
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
int single_ins::cnt = 0;
//餓漢試 init static value
/*
懶漢式的問題在于多線程調用的時候會出現問題,很可能同時建立出多個記憶體空間,
而不是單列了。
*/
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:10
b:20
1
0x7fc3880008c0
2
0x7fc3800008c0
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 }
這樣代碼如下:
pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&counter_mutex); //mutex 保護臨界區
if(myc == NULL) //兩次檢查
{
myc = new single_ins;
cnt++;
}
pthread_mutex_unlock(&counter_mutex); //mutex結束
跑出的結果如下:
a:10a:10
0x7f21f40008c0
現在就是正常的了。是以懶漢試單例遇到多線程一定要注意,餓漢試沒有問題。
當然這是一個小列子而已,線程安全是一個很大的話題,特别需要注意。
作者微信:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiInBnauUDZxgTMkFGZihjZidDMzcjMkVTNxgjMhZTO4EmN2EDNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.jpg)