本文來自EasyDarwin團隊Fantasy(fantasy(at)easydarwin.org)
一. EasyDarwin任務隊列實作
EasyDarwin的任務隊列是通過OSQueue類來組織的,操作方法有
EnQueue()插入一個節點
DeQueue()彈出一個節點
外面再經過一層封裝,OSQueue_Blocking(),該類對OSQueue的操作都是加鎖的,線程池的線程都是各自維護自己的隊列,EventContext主循環往裡投遞事件,線程讀取,處理。一邊寫一邊讀理論上來講不需要加鎖,但是這裡加鎖了。
原因是這樣的,我們看EnQueue和DeQueue的實作,隊列的前後兩個隊列之間是有聯系的,有fNext和fPrev的關系,如果在讀的時候,删除了fNext節點,就會出現空指針通路,導緻段錯誤,這個就像是STL疊代器失效。
二. 針對一讀一寫去鎖問題
大家可以學習一下核心的RCU機制,http://blog.csdn.net/nevil/article/details/7718375,通過緩存多份記憶體的方法避免讀寫沖突,舉個很簡單的例子,兩個程序需要通路同一片共享記憶體,為了提高效率,我們不加鎖(因為這兩個程序都不能阻塞),A會定時更新共享記憶體,B會查詢記憶體中的資料,A更新記憶體的操作不是原子操作,也就是說可能出現A更新一半,或者還沒更新剛剛清空記憶體的時候,B來查詢了,這樣就會出現錯誤的結果。于是我們申請兩塊記憶體,A寫的時候寫記憶體塊1,B查詢記憶體塊2,然後更換這兩塊記憶體的角色,這樣就不會有沖突了。
三. EasyDarwin無鎖隊列實作
實作起來也比較簡單,定一個合适長度的任務數組,目前定的是64
**#define MAX_QUEUE_ELEMS 64**
CyclicElem elems[MAX_QUEUE_ELEMS];
實作和OSQueue一模一樣的接口
GetLength()擷取有效任務個數
EnQueue()插入任務
DeQueue()彈出任務
int iread_pos;
int iwrite_pos;
int ivalid_elems; //定義讀寫位置,和有效元素個數變量。
初始化的時候都是0,如果處理的速度大于插入的速度,将不會有沖突,當讀的速度小于寫的速度的時候(這種情況下,我們認為隊列超載,将丢棄任務),是以實作的時候,隻要判斷當寫位置下一個位置就是讀的位置的時候,我們認為寫已經超過讀一圈了,任務隊列已滿。具體實作在OSQueue.h中。
擷取更多資訊
郵件:[email protected]
WEB:www.EasyDarwin.org
Copyright © EasyDarwin.org 2013-2016