我試圖找到(或實現)支持低優先級編寫器的讀/寫鎖,但在研究任何現有解決方案時都未能成功。支持低優先級編寫器的讀寫器鎖
我認爲低優先級作家的意思是:「將順利地排在新讀者或正常作家身上」。
肯定會導致飢餓,如果有讀者絡繹不絕,但是這可以解決或者與定時鎖變種(「試試定時低優先級的作家鎖」,然後切換到上超時正常鎖)或改變讀者的閱讀方式(可能會週期性地暫停閱讀短視窗)。
如果有任何文獻描述沿着這些線的東西,我還沒有找到它。
如果有一個已知的(正確!)解決方案利用常規鎖,我希望能得到一個描述。
我試圖找到(或實現)支持低優先級編寫器的讀/寫鎖,但在研究任何現有解決方案時都未能成功。支持低優先級編寫器的讀寫器鎖
我認爲低優先級作家的意思是:「將順利地排在新讀者或正常作家身上」。
肯定會導致飢餓,如果有讀者絡繹不絕,但是這可以解決或者與定時鎖變種(「試試定時低優先級的作家鎖」,然後切換到上超時正常鎖)或改變讀者的閱讀方式(可能會週期性地暫停閱讀短視窗)。
如果有任何文獻描述沿着這些線的東西,我還沒有找到它。
如果有一個已知的(正確!)解決方案利用常規鎖,我希望能得到一個描述。
我什麼都不知道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
類,它可以優先考慮讀者而不是寫作者,這樣如果有的話讀者是否在等待/進入。再次,不完全是您想要的行爲,因爲它會影響給定鎖上的所有作者,而不僅僅是特定的鎖。
恐怕你不得不編寫自己的優先鎖,有兩個編寫器喚醒隊列。
感謝您的詳細回覆。你的一些想法(延遲旋轉)在我最初的想法中,儘管我不知道你的許多例子。 – mmocny
請參閱http://home.roadrunner.com/~hinnant/mutexes/locking.html以獲取在C++中實現讀/寫鎖的一些開源代碼。不幸的是,這個鏈接也沒有解決原始問題。但它確實解決了與此答案中提出的問題非常相似的問題。這個實現中的讀/寫優先級是「公平的」。 –
關閉我的頭頂,你會想是這樣的:
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()應該是可行的。
糟糕...忘了頂部的關鍵writers.push(...)。 – mcmcc
我很想知道現有的實現,但如果沒有,我可以想到的最簡單的方法是爲低優先級查詢創建一個單獨的隊列,並定期合併到主隊列中。它與你提到的定時鎖並沒有什麼不同,只是即使隊列爲空也會有延遲 - 解決這個問題的一種方法是在需要時添加一個「空隊列」事件。 –