臨界資源:
新華ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為創(chuàng)新互聯(lián)的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18982081108(備注:SSL證書合作)期待與您的合作!一個進(jìn)程的資源對于運行在它內(nèi)部的線程是共享的,一次只允許一個線程使用的資源叫做臨界資源
臨界區(qū):
訪問臨界資源的那段程序叫做臨界區(qū)
線程的同步:
同步就是協(xié)同步調(diào),按照預(yù)定的先后順序執(zhí)行。
“同”字應(yīng)是指協(xié)同、協(xié)助、互相配合。
線程的互斥:
某一資源同時只允許一個訪問者對其進(jìn)行訪問,具有唯一性和排它性。
但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的。
互斥量(mutex)
多個線程同時訪問共享數(shù)據(jù)時,經(jīng)常會發(fā)生沖突,因此常常引入互斥鎖來解決這個問題。
沖突:例如對一個全局變量g_var進(jìn)行加一操作,這樣的操作需要三條指令來完成:(1、把該變量的值從內(nèi)存讀到寄存器;2、寄存器進(jìn)行加一操作;3、把修改后的值寫回內(nèi)存),因為這三條指令的執(zhí)行不是原子操作,有可能線程1執(zhí)行了第一步(把變量值讀到寄存器),此時內(nèi)核調(diào)度線程2,線程2也把該值讀到寄存器,它們都進(jìn)行加一操作后寫回內(nèi)存,導(dǎo)致最后結(jié)果只加了一次,而我們希望是兩次。
解決:引入互斥鎖,獲得鎖的線程可以對變量進(jìn)行“讀-修改-寫”操作,這個操作是原子的,完成這個操作后釋放鎖給別的線程,沒有獲得鎖的線程只能等待而不能訪問該共享數(shù)據(jù)。
有關(guān)函數(shù):
1.互斥鎖的初始化及銷毀
其中初始化既可以使用函數(shù)pthread_mutex_init(),也可以定義pthread_mutex_t類型的變量mutex,并賦值PTHREAD_MUTEX_INITIALIZER
2.對mutex的加鎖及解鎖
一個線程可以調(diào)用pthread_mutex_lock獲得Mutex,如果這時另一個線程已經(jīng)調(diào)用pthread_mutex_lock獲得了該Mutex,則當(dāng)前線程需要掛起等待,直到另一個線程調(diào)用pthread_mutex_unlock釋放Mutex,當(dāng)前線程被喚醒,才能獲得該Mutex并繼續(xù)執(zhí)行。
如果一個線程既想獲得鎖,又不想掛起等待,可以調(diào)用pthread_mutex_trylock,如果Mutex已經(jīng)被另一個線程獲得,這個函數(shù)會失敗返回EBUSY,而不會使線程掛起等待。
Mutex的lock和unlock的偽碼(以x86的xchg指令為例):
不使用互斥量代碼:
#include#include void *thread(void *arg) { int count=2000; while(count-- >0){ int var=g_var; printf("this is thread%d,g_var=%d\n",(int)arg,g_var); g_var=var+1; } } int main() { pthread_t tid1,tid2; if(pthread_create(&tid1,NULL,thread,(void*)1)!=0){ printf("creat tid1 is failed\n"); } if(pthread_create(&tid1,NULL,thread,(void*)2)!=0){ printf("creat tid1 is failed\n"); } pthread_join(tid1,NULL); pthread_join(tid2,NULL); return 0; }
運行結(jié)果:
第一次運行線程1和線程2一共加了2275次
第二次運行一共把g_var加了2000次
使用互斥量實現(xiàn)代碼:
include#include //pthread_mutex_t mutex_lock=PTHREAD_MUTEX_INITIALIZER; struct info { int _var; pthread_mutex_t *_mutex_lock; }info; int g_var=0; void *thread(void *arg) { struct info* _lock=(struct info*)arg; int count=2000; while(count-- >0){ pthread_mutex_lock(_lock->_mutex_lock); int var=g_var; printf("this is thread%d,g_var=%d\n",_lock->_var,g_var); g_var=var+1; pthread_mutex_unlock(_lock->_mutex_lock); } } int main() { pthread_t tid1,tid2; pthread_mutex_t mutex_lock; int err=pthread_mutex_init(&mutex_lock,NULL); if(err!=0){ printf("%s\n",strerror(err)); } struct info info1; info1._var=1; info1._mutex_lock=&mutex_lock; if(pthread_create(&tid1,NULL,thread,&info1)!=0){ printf("creat tid1 is failed\n"); } struct info info2; info2._var=2; info2._mutex_lock=&mutex_lock; if(pthread_create(&tid2,NULL,thread,&info2)!=0){ printf("creat tid2 is failed\n"); } pthread_join(tid1,NULL); pthread_join(tid2,NULL); err=pthread_mutex_destroy(&mutex_lock); if(err!=0){ printf("%s\n",strerror(err)); } return 0; }
運行結(jié)果:
線程1和線程2共執(zhí)行了4000次
總結(jié):當(dāng)一個線程已經(jīng)獲得鎖,另一個線程需掛起等待,當(dāng)該線程釋放鎖后,會喚醒正在等待線程。每個mutex都有一個等待隊列,當(dāng)線程掛起時,就加入該等待隊列,狀態(tài)設(shè)置為睡眠。一個線程要喚醒別的線程,只需要從等待隊列中取出一項加入就緒隊列并把它的狀態(tài)設(shè)置為就緒。
有的時候一個線程會兩次獲得鎖,第一次正常獲得,第二次獲得所得時候發(fā)現(xiàn)鎖已經(jīng)被別占用,它就會掛起,導(dǎo)致自己占用了鎖卻處于掛起狀態(tài),這樣就產(chǎn)生了死鎖。
死鎖:
產(chǎn)生死鎖的原因
1、進(jìn)程資源不足
2、進(jìn)程推進(jìn)的順序不合適
3、系統(tǒng)資源的分配不當(dāng)
產(chǎn)生死鎖的必要條件:
1、互斥條件:一個資源一次只能被一個進(jìn)程使用
2、請求與保持條件:一個已經(jīng)進(jìn)程因請求資源而阻塞,對已獲得的資源保持不放
3、不剝奪條件:進(jìn)程已獲得的資源,在沒使用完之前,不能強行剝奪
4、循環(huán)等待條件:若干個進(jìn)程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系
產(chǎn)生死鎖時,以上四個必要條件一定都成立。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機、免備案服務(wù)器”等云主機租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。