您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“C++如何解決單例懶漢式和多線(xiàn)程問(wèn)題”,內(nèi)容簡(jiǎn)而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“C++如何解決單例懶漢式和多線(xiàn)程問(wèn)題”這篇文章吧。
單例懶漢式和多線(xiàn)程問(wèn)題
作為單例模式,是在整個(gè)程序運(yùn)行期間只會(huì)建立一份內(nèi)存空間,為了達(dá)到這個(gè)目標(biāo)
1、需要將構(gòu)造函數(shù)設(shè)置為私有成員
2、需要一個(gè)私有的靜態(tài)指針指向自身
3、需要一個(gè)公有的靜態(tài)函數(shù)將這個(gè)上面的靜態(tài)指針露出來(lái)
如下的代碼就是一個(gè)懶漢式的單例
點(diǎn)擊(此處)折疊或打開(kāi)
#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();
}
但是上面的代碼有明顯的問(wèn)題,就是遇到多線(xiàn)程的情況下,因?yàn)槎鄠€(gè)線(xiàn)程如果同事創(chuàng)建內(nèi)存,由于彼此之間
并不能及時(shí)檢查到內(nèi)存已經(jīng)分配,會(huì)分配多個(gè)內(nèi)存,這個(gè)時(shí)候我們至少需要一個(gè)線(xiàn)程間同步手段來(lái)讓他們之間
串行的執(zhí)行,這個(gè)時(shí)候就涉及到兩次檢查(double check)
如果沒(méi)有mutex保護(hù)就是下面這個(gè)程序:
點(diǎn)擊(此處)折疊或打開(kāi)
#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); //故意拖長(zhǎng)構(gòu)造函數(shù)執(zhí)行時(shí)間,造成懶漢式多線(xiàn)程問(wèn)題
cout<<"con end\n";
}
static single_ins* myc;//單例需要一個(gè)靜態(tài)指針
static int cnt;//構(gòu)造調(diào)用次數(shù)統(tǒng)計(jì)
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() //函數(shù)獲得指針值賦給靜態(tài)成員指針變量
{
//懶漢式
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;
/*
懶漢式的問(wèn)題在于多線(xiàn)程調(diào)用的時(shí)候會(huì)出現(xiàn)問(wèn)題,很可能同時(shí)建立出多個(gè)內(nèi)存空間,
而不是單列了。
*/
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();
}
會(huì)跑出結(jié)果
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個(gè)不同的內(nèi)存空間 這就不對(duì)了,而且可以看到構(gòu)造函數(shù)
調(diào)用了3次
為此我們使用mutex來(lái)保護(hù)臨時(shí)
如下:
static single_ins* setp() //函數(shù)獲得指針值賦給靜態(tài)成員指針變量
39 {
40 //懶漢式
41 if(myc == NULL)
42 {
43 pthread_mutex_lock(&counter_mutex); //mutex 保護(hù)臨界區(qū)
44 if(myc == NULL) //兩次檢查
45 {
46 myc = new single_ins;
47 cnt++;
48 }
49 pthread_mutex_unlock(&counter_mutex); //mutex結(jié)束
50 }
這樣代碼如下:
點(diǎn)擊(此處)折疊或打開(kāi)
#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); //故意拖長(zhǎng)構(gòu)造函數(shù)執(zhí)行時(shí)間,造成懶漢式多線(xiàn)程問(wèn)題
cout<<"con end\n";
}
static single_ins* myc;//單例需要一個(gè)靜態(tài)指針
static int cnt;//構(gòu)造調(diào)用次數(shù)統(tǒng)計(jì)
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() //函數(shù)獲得指針值賦給靜態(tài)成員指針變量
{
//懶漢式
if(myc == NULL)
{
pthread_mutex_lock(&counter_mutex); //mutex 保護(hù)臨界區(qū)
if(myc == NULL) //兩次檢查
{
myc = new single_ins;
cnt++;
}
pthread_mutex_unlock(&counter_mutex); //mutex結(jié)束
}
//懶漢式
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;
/*
懶漢式的問(wèn)題在于多線(xiàn)程調(diào)用的時(shí)候會(huì)出現(xiàn)問(wèn)題,很可能同時(shí)建立出多個(gè)內(nèi)存空間,
而不是單列了。
*/
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();
}
跑出的結(jié)果如下:
con begin
con end
a:10a:10
b:20
1
0x7f21f40008c0
b:20
1
0x7f21f40008c0
a:10
b:20
1
0x7f21f40008c0
現(xiàn)在就是正常的了。所以懶漢試單例遇到多線(xiàn)程一定要注意,餓漢試沒(méi)有問(wèn)題。
當(dāng)然這是一個(gè)小列子而已,線(xiàn)程安全是一個(gè)很大的話(huà)題,特別需要注意。
以上是“C++如何解決單例懶漢式和多線(xiàn)程問(wèn)題”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。