[英]Fast counting semaphore on Windows?
首先,我知道可以使用互斥量和條件變量來實現它,但是我想要盡可能高效的實現。 沒有爭用時,我想要一條帶有快速路徑的信號燈。 在Linux上,使用futex很容易。 例如,這是一個等待:
if (AtomicDecremenIfPositive(_counter) > 0) return; // Uncontended
AtomicAdd(&_waiters, 1);
do
{
if (syscall(SYS_futex, &_counter, FUTEX_WAIT_PRIVATE, 0, nullptr, nullptr, 0) == -1) // Sleep
{
AtomicAdd(&_waiters, -1);
throw std::runtime_error("Failed to wait for futex");
}
}
while (AtomicDecrementIfPositive(_counter) <= 0);
AtomicAdd(&_waiters, -1);
並發布:
AtomicAdd(&_counter, 1);
if (Load(_waiters) > 0 && syscall(SYS_futex, &_counter, FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0) == -1) throw std::runtime_error("Failed to wake futex"); // Wake one
最初,我認為Windows僅使用NtWaitForKeyedEvent()。 問題在於它不是直接替換,因為它在進入內核之前不會自動檢查_counter的值,因此可能會錯過NtReleaseKeyedEvent()的喚醒。 更糟糕的是,NtReleaseKeyedEvent()會阻塞。 最好的解決方案是什么?
Windows具有帶有CreateSemaphore的本地信號量。 除非並且直到您遇到某種形式的性能問題(以正常方式進行操作),否則您甚至不應該考慮脆弱或特定於硬件的優化。
我認為這樣的事情應該起作用:
// bottom 16 bits: post count
// top 16 bits: wait count
struct Semaphore { unsigned val; }
wait(struct Semaphore *s)
{
retry:
do
old = s->val;
if old had posts (bottom 16 bits != 0)
new = old - 1
wait = false
else
new = old + 65536
wait = true
until successful CAS of &s->val from old to new
if wait == true
wait on keyed event
goto retry;
}
post(struct Semaphore *s)
{
do
old = s->val;
if old had waiters (top 16 bits != 0)
// perhaps new = old - 65536 and remove the "goto retry" above?
// not sure, but this is safer...
new = old - 65536 + 1
release = true
else
new = old + 1
release = false
until successful CAS of &s->val from old to new
if release == true
release keyed event
}
編輯 :就是說,我不確定這對您有很大幫助。 您的線程池通常應該足夠大,以使線程始終可以處理您的請求。 這意味着不僅等待,而且發帖總是會走慢的路,然后轉到內核。 因此,計數信號量可能是您根本不關心僅用戶空間的快速路徑的一個原語。 股票Win32信號量應該足夠好。 就是說,我很高興被證明是錯誤的!
我支持您的第一個想法,例如臨界區和條件變量。 關鍵部分足夠快,並且在進入睡眠狀態之前確實使用了互鎖操作。 或者,您可以嘗試使用SRWLocks而不是關鍵部分。 條件變量(和SRWLocks)非常快-它們的唯一問題是XP上沒有條件,但也許您不需要針對此平台。
Qt具有諸如QMutex,QSemaphore之類的各種功能,它們以與您在問題中所呈現的精神相同的方式實現。
實際上,我建議用操作系統提供的常規同步原語替換futex東西。 沒關系,因為那畢竟是一條緩慢的道路。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.