簡體   English   中英

在Windows上快速計數信號量?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM