【VS开发】C++线程安全
我們是多么渴望各種C++類都是多線程安全的,然而一旦涉及到對(duì)象間的交互,這樣的渴望可能就只能是奢望了。下面,我們以設(shè)計(jì)一個(gè)雙向鏈結(jié)點(diǎn)為例,看看要使其多線程安全將會(huì)帶來(lái)一些什么問(wèn)題。
class?DoublyLinedNode{
???????DoublyLinedNode*?pPrevNode_;
???????DoublyLinedNode*?pNextNode_;
?
public:
???????DoublyLinedNode() :?pPrevNode_(0),?pNextNode_(0){}
???????virtual?~DoublyLinedNode();
?
public:
???????const?DoublyLinedNode*?GetPrevNode()?const{return?pPrevNode_;}
???????const?DoublyLinedNode*?GetNextNode()?const{return?pNextNode_;}
?
public:
???????void?InsertPrevNode(DoublyLinedNode*?p);
???????void?InsertNextNode(DoublyLinedNode*?p);
???????void?Break();
};
這是一個(gè)簡(jiǎn)單的雙向鏈結(jié)點(diǎn)類,我們就討論討論其Break接口,這個(gè)接口的作用是使結(jié)點(diǎn)從其所在的鏈中斷開(kāi),如圖:
?
它的實(shí)現(xiàn)可能是這樣的:
void?DoublyLinedNode::Break()
{
???????if?(pPrevNode_)
???????{
??????????????pPrevNode_->pNextNode_?=?pNextNode_;
???????}
???????if?(pNextNode_)
???????{
??????????????pNextNode_->pPrevNode_?=?pPrevNode_;
???????}
???????pPrevNode_?= 0;
???????pNextNode_?= 0;
}
這個(gè)實(shí)現(xiàn)是單線程模式的,沒(méi)有多線程安全性。
第一次嘗試:
void?DoublyLinedNode::Break()
{
Lock();
???????if?(pPrevNode_)
???????{
??????????????pPrevNode_->pNextNode_?=?pNextNode_;
???????}
???????if?(pNextNode_)
???????{
??????????????pNextNode_->pPrevNode_?=?pPrevNode_;
???????}
???????pPrevNode_?= 0;
???????pNextNode_?= 0;
???????UnLock();
}
我們第一次嘗試將這個(gè)接口的代碼用多線程鎖鎖住了,然而問(wèn)題很明顯:
if?(pPrevNode_)
{
???????pPrevNode_->pNextNode_?=?pNextNode_;
}
if?(pNextNode_)
{
???????pNextNode_->pPrevNode_?=?pPrevNode_;
}
我們這兩個(gè)對(duì)前向和后向結(jié)點(diǎn)的操作是修改另外兩個(gè)對(duì)象的內(nèi)部狀態(tài),多線程中,可能在此時(shí)正好有其他線程在對(duì)這兩個(gè)對(duì)象進(jìn)行操作(訪問(wèn)),或許程序就會(huì)因此而崩潰。
第二次嘗試:
void?DoublyLinedNode::Break()
{
Lock();
???????if?(pPrevNode_)
???????{
??????????????pPrevNode_->SetNextNode(pNextNode_);?// SetNextNode同樣添加了鎖保護(hù)
???????}
???????if?(pNextNode_)
???????{
??????????????pNextNode_->SetPrevNode(pPrevNode_);?// SetPrevNode同樣添加了鎖保護(hù)
???????}
???????pPrevNode_?= 0;
???????pNextNode_?= 0;
???????UnLock();
}
這第二次嘗試將我們對(duì)前向和后繼結(jié)點(diǎn)的內(nèi)部狀態(tài)的直接修改改成了對(duì)其接口的調(diào)用,我們?cè)噲D通過(guò)在其各種接口中加鎖來(lái)達(dá)到多線程安全的目的。然而這卻引入了新的問(wèn)題,我們?cè)谝粋€(gè)被鎖住的代碼中進(jìn)行了又調(diào)用了另外會(huì)使用鎖的代碼,這最可能引發(fā)的問(wèn)題就是資源競(jìng)爭(zhēng),而在我們這次嘗試中引如的問(wèn)題的確就是資源競(jìng)爭(zhēng),導(dǎo)致死鎖:
?
我們?cè)诓煌€程中對(duì)結(jié)點(diǎn)1和結(jié)點(diǎn)2同時(shí)調(diào)用Break,當(dāng)1申請(qǐng)到自身的鎖之后,準(zhǔn)備調(diào)用2的接口,此時(shí)2也申請(qǐng)到了自身的鎖,準(zhǔn)備調(diào)用1的接口。由于1已經(jīng)占有了自身的鎖,2也占有了自身的鎖,那么1將會(huì)在調(diào)用2的接口的地方等待2的鎖,而2將會(huì)在調(diào)用1的接口的地方等待1,?1和2的相互等待就形成了死鎖。
第三次嘗試:
void?DoublyLinedNode::Break()
{
Lock();
???????if?(pPrevNode_)
???????{
pPrevNode_->?Lock();
??????????????pPrevNode_->SetNextNode(pNextNode_);
pPrevNode_->?UnLock?();
???????}
???????if?(pNextNode_)
???????{
pNextNode_->?Lock();
??????????????pNextNode_->SetPrevNode(pPrevNode_);
pNextNode_->?UnLock?();
???????}
???????pPrevNode_?= 0;
???????pNextNode_?= 0;
???????UnLock();
}
這次嘗試顯得比較愚蠢,將外部對(duì)象加鎖的過(guò)程提到了自身Break當(dāng)中效果和第二次嘗試是一樣的,沒(méi)有得到任何的改善。
第四次嘗試:
void?DoublyLinedNode::Break()
{
SharedLock();
???????if?(pPrevNode_)
???????{
??????????????pPrevNode_->SetNextNode(pNextNode_);
???????}
???????if?(pNextNode_)
???????{
??????????????pNextNode_->SetPrevNode(pPrevNode_);
???????}
???????pPrevNode_?= 0;
???????pNextNode_?= 0;
???????SharedUnLock();
}
這次嘗試取得了一定的成功,對(duì)于這些關(guān)系密切,存在相互調(diào)用的對(duì)象,我們使用了共享鎖,它的確將我們的多線程訪問(wèn)沖突和死鎖問(wèn)題解決了,但是這個(gè)共享鎖的實(shí)現(xiàn)難度是相當(dāng)大的,你必須要保證可能產(chǎn)生相互調(diào)用的對(duì)象都要進(jìn)行鎖共享,那么你對(duì)于增加、修改、刪除對(duì)象這些管理工作將會(huì)變得極度困難,稍有差池就會(huì)引發(fā)問(wèn)題,而且別人在使用你的類的時(shí)候也同樣需要處處小心,這不是我們所期望的。
?
以上我們進(jìn)行了四次嘗試將我們的雙向鏈結(jié)點(diǎn)類設(shè)計(jì)成多線程安全,顯然我們已經(jīng)筋疲力盡,卻未能達(dá)到滿意的效果。
在這里我建議大家設(shè)計(jì)這種類的時(shí)候盡量設(shè)計(jì)成單線程模式,在框架設(shè)計(jì)中去考慮多線程問(wèn)題,比如使用單線程訪問(wèn)對(duì)象,而模塊間使用異步通信來(lái)進(jìn)行交互等。
?
多線程編程的確非常困難,C++在這方面又表現(xiàn)得力不從心,我在這里引入這個(gè)問(wèn)題旨在于告誡大家在對(duì)待多線程問(wèn)題上一定要細(xì)心細(xì)心再細(xì)心。
轉(zhuǎn)載于:https://www.cnblogs.com/huty/p/8518634.html
總結(jié)
以上是生活随笔為你收集整理的【VS开发】C++线程安全的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: leetcode 之Median of
- 下一篇: 2011年日本大地震哪些国家参与救援20