2011-02-22 61 views
4

我試圖找到(或實現)支持低優先級編寫器的讀/寫鎖,但在研究任何現有解決方案時都未能成功。支持低優先級編寫器的讀寫器鎖

我認爲低優先級作家的意思是:「將順利地排在新讀者或正常作家身上」。

肯定會導致飢餓,如果有讀者絡繹不絕,但是這可以解決或者與定時鎖變種(「試試定時低優先級的作家鎖」,然後切換到上超時正常鎖)或改變讀者的閱讀方式(可能會週期性地暫停閱讀短視窗)。

如果有任何文獻描述沿着這些線的東西,我還沒有找到它。

如果有一個已知的(正確!)解決方案利用常規鎖,我希望能得到一個描述。

+0

我很想知道現有的實現,但如果沒有,我可以想到的最簡單的方法是爲低優先級查詢創建一個單獨的隊列,並定期合併到主隊列中。它與你提到的定時鎖並沒有什麼不同,只是即使隊列爲空也會有延遲 - 解決這個問題的一種方法是在需要時添加一個「空隊列」事件。 –

回答

3

我什麼都不知道100%像你的建議,但有是接近一些現有的接口:

許多現有的R/W鎖的API有一個「嘗試鎖定」界面,像pthread_rwlock_trywrlock()在UN * X系統。這些都是免等待的,只有在沒有人擁有它的情況下才會獲得鎖定,也不會等待。

您通常會使用此旋轉鎖定和/或人爲延遲嘗試代碼(退格)。即有這樣的代碼:

for (count = 0; count < MAX_SPINS && (locked = trywrlock(lock)); count++); 
if (locked) { 
    delay(some_backoff); 
    wrlock(lock);   /* or try spinning loop above again ? */ 
} 

不幸的是,這不是你所要求的;它遲早會得到鎖定,但是由於(可能不必要的)退避,低優先級的作者將在CPU上旋轉和/或以延遲的方式得到它。

Solaris內核有一個接口rw_tryupgrade(9f),可用於測試是否當前線程是沒有作家等待,如果是這樣的鎖的唯一讀者,鎖升級爲獨佔/寫,也就是你喜歡的代碼:

if (!rw_tryenter(lock, RW_WRITER)) { 
    rw_enter(lock, RW_READER); /* this might wait for a writer */ 
    if (!rw_tryupgrade(lock)) { /* this fails if >1 reader/writer waiting */ 
     /* do what you must to if you couldn't get in immediately */ 
    } 
} 

這是一個有點接近你問什麼,但還是不完全一樣 - 如果失敗的話,你必須放下readlock,可能回退(等待),reaquire的readlock,嘗試升級。這個過程再次相當於旋轉。另外,許多UNIX系統至少實際上以調度優先級的順序執行服務器喚醒;所以你必須在嘗試普通之前讓你的線程最低優先級(如果必要的話,人爲地),等待wrlock()呼叫;當線程正在等待時,誰想要相同的寫鎖,在調度程序工作的前提下,它會在它之前得到它。儘管在多處理器/核心系統上不一定能保證...

最後,SymbianOS(Symbian^3版本)有一個RRWlock類,它可以優先考慮讀者而不是寫作者,這樣如果有的話讀者是否在等待/進入。再次,不完全是您想要的行爲,因爲它會影響給定鎖上的所有作者,而不僅僅是特定的鎖。

恐怕你不得不編寫自己的優先鎖,有兩個編寫器喚醒隊列。

+0

感謝您的詳細回覆。你的一些想法(延遲旋轉)在我最初的想法中,儘管我不知道你的許多例子。 – mmocny

+0

請參閱http://home.roadrunner.com/~hinnant/mutexes/locking.html以獲取在C++中實現讀/寫鎖的一些開源代碼。不幸的是,這個鏈接也沒有解決原始問題。但它確實解決了與此答案中提出的問題非常相似的問題。這個實現中的讀/寫優先級是「公平的」。 –

0

關閉我的頭頂,你會想是這樣的:

class PriorityRWLock 
{ 
    int    rwcount; 
    mutex    mtx; 
    condition_variable cv; 
    priority_queue<writer_info> writers; 
}; 

...和PriorityRWLock :: acquire_write_lock()看起來是這樣的:

lock_guard raii(mtx); 

do { 
if (rwcount==0) // == no read or write locks 
{ 
    if (writers.top().thread == thread::self()) 
    { rwcount = -1; writers.pop_front(); break; } // == exclusive write access 
    else 
    { 
    // wake up the waiting thread(s) and sleep 
    writers.push(writer_info(thread::self(),priority)); 
    cv.notify_all(); 
    cv.wait(mtx); 
    } 
} 
else 
{ cv.wait(mtx); } // sleep 
} while (true); 

..或者接近於此。

它不會過於高效。你真的希望將rwcount存儲在atomic_int或類似的地方,但是對condition_variable的需求排除了這一點。

由於可能需要間歇性等待(),所以定時鎖定會非常棘手。 try_write_lock()應該是可行的。

+0

糟糕...忘了頂部的關鍵writers.push(...)。 – mcmcc