這篇文章主要講解了“Libtask源碼解析之如何理解鎖”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Libtask源碼解析之如何理解鎖”吧!

成都創(chuàng)新互聯(lián)主要為客戶提供服務項目涵蓋了網頁視覺設計、VI標志設計、全網營銷推廣、網站程序開發(fā)、HTML5響應式重慶網站建設公司、移動網站建設、微商城、網站托管及企業(yè)網站維護、WEB系統(tǒng)開發(fā)、域名注冊、國內外服務器租用、視頻、平面設計、SEO優(yōu)化排名。設計、前端、后端三個建站步驟的完善服務體系。一人跟蹤測試的建站服務標準。已經為成都PVC花箱行業(yè)客戶提供了網站設計服務。
libtask中其實不需要鎖,因為libtask中協(xié)程是非搶占式的,不存在競態(tài)條件。但是libtask還是實現(xiàn)了一套鎖的機制。我們看一下這個鎖機制的實現(xiàn)。首先我們看一下結構體。
struct QLock { // 鎖持有者 Task *owner; // 等待該鎖的隊列 Tasklist waiting; };接著我們看一下鎖的操作。
加鎖
static int _qlock(QLock *l, int block) { // 鎖沒有持有者,則置當前協(xié)程為持有者,直接返回,1表示加鎖成功 if(l->owner == nil){ l->owner = taskrunning; return 1; } // 非阻塞,則直接返回,0表示加鎖失敗 if(!block) return 0; // 插入等待鎖隊列 addtask(&l->waiting, taskrunning); taskstate("qlock"); // 切換到其他協(xié)程 taskswitch(); // 切換回來時,如果持有鎖的協(xié)程不是當前協(xié)程,則異常退出,因為只有持有鎖才會被切換回來,見unqlock if(l->owner != taskrunning){ fprint(2, "qlock: owner=%p self=%p oops\n", l->owner, taskrunning); abort(); } return 1; }如果當前鎖沒有持有者,則當前協(xié)程X就變成鎖的持有者,否則把協(xié)程X插入等待鎖隊列中,然后讓出cpu,切換到其他協(xié)程。當后續(xù)鎖被釋放并被協(xié)程X持有時,協(xié)程X就會被喚醒繼續(xù)持續(xù)。加鎖可以分為阻塞和非阻塞兩種模式。非阻塞就是加鎖失敗也不會切換協(xié)程。
// 阻塞式加鎖 void qlock(QLock *l) { _qlock(l, 1); } // 非阻塞式加鎖 int canqlock(QLock *l) { return _qlock(l, 0); }釋放鎖
接下來我們看一下釋放鎖的邏輯
// 釋放鎖 void qunlock(QLock *l) { Task *ready; // 鎖并沒有持有者,異常退出 if(l->owner == 0){ fprint(2, "qunlock: owner=0\n"); abort(); } // 如果還有協(xié)程在等待該鎖,則置為持有者,并且從等待隊列中刪除,然后修改狀態(tài)為就緒并加入就緒隊列 if((l->owner = ready = l->waiting.head) != nil){ deltask(&l->waiting, ready); taskready(ready); } }當鎖被釋放時,如果還有協(xié)程在等待該鎖,則從等待隊列中摘取一個節(jié)點,然后變成鎖的持有者并從等待隊列中刪除。最后插入就緒隊列等待調度。以上是一種互斥鎖的實現(xiàn)。下面我們再來看一下讀寫鎖機制,讀寫鎖也是互斥的,但是在某些情況下也可以共享。我們看一下讀寫鎖的數(shù)據(jù)結構。
struct RWLock { // 正在讀的讀者個數(shù) int readers; // 當前正在寫的寫者,只有一個 Task *writer; // 等待讀和寫的隊列 Tasklist rwaiting; Tasklist wwaiting; };接著我看一下加鎖邏輯。
加讀鎖
// 加讀鎖 static int _rlock(RWLock *l, int block) { /* 沒有正在寫并且沒有等待寫,則加鎖成功,并且讀者數(shù)加一 */ if(l->writer == nil && l->wwaiting.head == nil){ l->readers++; return 1; } // 非阻塞則直接返回 if(!block) return 0; // 插入等待讀隊列 addtask(&l->rwaiting, taskrunning); taskstate("rlock"); // 切換上下文 taskswitch(); // 切換回來了,說明加鎖成功 return 1; }當且僅當沒有正在寫的寫者和等待寫的寫者時,才能加讀鎖成功,否則根據(jù)加鎖模式進行下一步處理,直接返回加鎖失敗或者插入等待隊列,然后切換到其他協(xié)程。我們看到當有一個等待寫的協(xié)程時(l->wwaiting.head != nil),則后續(xù)的讀者就無法加鎖成功,而是被插入等待隊列,否則可能會引起寫者饑餓。
加寫鎖
// 加寫鎖 static int _wlock(RWLock *l, int block) { // 沒有正在寫并且沒有正在讀,則加鎖成功,并置寫者為當前協(xié)程 if(l->writer == nil && l->readers == 0){ l->writer = taskrunning; return 1; } // 非阻塞則直接返回 if(!block) return 0; // 加入等待寫隊列 addtask(&l->wwaiting, taskrunning); taskstate("wlock"); // 切換 taskswitch(); // 切換回來說明拿到鎖了 return 1; }當且僅當沒有正在寫的寫者和沒有正在讀的讀者時,才能加寫鎖成功。否則類似加讀鎖一樣處理。
釋放讀鎖
// 釋放讀鎖 void runlock(RWLock *l) { Task *t; // 讀者減一,如果等于0并且有等待寫的協(xié)程,則隊列第一個協(xié)程持有該鎖 if(--l->readers == 0 && (t = l->wwaiting.head) != nil){ deltask(&l->wwaiting, t); l->writer = t; taskready(t); } }持有讀鎖,說明當前肯定沒有正在寫的寫者,但是可能有等待寫的寫者和等待讀的讀者(因為有等待寫的寫者導致無法加鎖成功)。當釋放讀鎖時,如果還有其他讀者,則其他讀者可以繼續(xù)持有鎖,因為讀者可以共享讀鎖,而寫者保持原來狀態(tài)。如果這時候沒有讀者但是有等待寫的寫者,則從隊列中選擇第一個節(jié)點成為鎖的持有者,其他的寫者則繼續(xù)等待,因為寫者不能共享寫鎖。
釋放寫鎖
// 釋放寫鎖 void wunlock(RWLock *l) { Task *t; // 沒有正在寫,異常退出 if(l->writer == nil){ fprint(2, "wunlock: not locked\n"); abort(); } // 置空,沒有協(xié)程正在寫 l->writer = nil; // 有正在讀,異常退出,寫的時候,是無法讀的 if(l->readers != 0){ fprint(2, "wunlock: readers\n"); abort(); } // 釋放寫鎖時,優(yōu)先讓讀者持有鎖,因為讀者可以共享持有鎖,提高并發(fā) // 讀可以共享,把等待讀的協(xié)程都加入就緒隊列,并持有鎖 while((t = l->rwaiting.head) != nil){ deltask(&l->rwaiting, t); l->readers++; taskready(t); } // 釋放寫鎖時,如果又沒有讀者,并且有等待寫的協(xié)程,則隊列的第一個等待寫的協(xié)程持有鎖 if(l->readers == 0 && (t = l->wwaiting.head) != nil){ deltask(&l->wwaiting, t); l->writer = t; taskready(t); } }持有寫鎖,可能有等待寫的寫者和等待讀的讀者。這里是讀者優(yōu)先持有鎖,因為讀者可以共享持有鎖,提高并發(fā),如果沒有讀者,則再判斷寫者。
感謝各位的閱讀,以上就是“Libtask源碼解析之如何理解鎖”的內容了,經過本文的學習后,相信大家對Libtask源碼解析之如何理解鎖這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關知識點的文章,歡迎關注!
當前文章:Libtask源碼解析之如何理解鎖
文章地址:http://chinadenli.net/article12/ipjhdc.html
成都網站建設公司_創(chuàng)新互聯(lián),為您提供網站內鏈、服務器托管、網站維護、響應式網站、品牌網站設計、面包屑導航
聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)