Do semaphores prevent instruction reordering?

前端 未结 3 1460
栀梦
栀梦 2021-01-13 05:00

I was looking for an awaitable equivalent of lock statements in C#. Some people suggest using a binary SemaphoreSlim in the following way:

await         


        
相关标签:
3条回答
  • 2021-01-13 05:00

    I am no expert in memory models, but now I think that we have those guarantees.

    As Servy has pointed out, both the Wait and Release methods use a Monitor under the hood. However, a Monitor on its own may not be enough.

    At the end of the Wait method, right before the Monitor.Exit call, a volatile field is decremented.

    if (lockTaken)
    { 
        m_waitCount--; //m_waitCount is volatile
        Monitor.Exit(m_lockObj); 
    } 
    

    As far as I understand, the decrement operator used on a volatile field will introduce both the 'acquire' and 'release' operations, blocking the following instructions from being reordered before it.

    As for the Release method, the situation is analogous. At the beginning we have both the lock acquisition and volatile read-write operation as well.

    lock (m_lockObj) 
    {
        //m_currentCount is volatile
        if (m_maxCount - m_currentCount < releaseCount)
        {
            throw new SemaphoreFullException(); 
        }
    
        m_currentCount += releaseCount;
    

    Special thanks to Joe Duffy for pointing out the importance of the volatile fields in the SemaphoreSlim.

    EDIT: An example demonstrating a situation where the locks on their own (without additional volatile operations) may not be enough.

    // Semaphore.Wait()
    lock (syncRoot)
    {
        // (1)
        // acquire semaphore
    }
    // end of Semaphore.Wait()
    
    // the critical section guarded by the 'semaphore lock' (2)
    
    // Semaphore.Release()
    lock (syncRoot)
    {
        // release semaphore
    }
    // end of Semaphore.Release()
    

    A read instruction from the critical section (2) could be reordered to (1), when the semaphore is not yet acquired (another thread might still be working in a critical section).

    0 讨论(0)
  • 2021-01-13 05:07

    SemaphoreSlim, and pretty much all of the other synchronization constructs, are built using a Monitor (or other types that are built on top of a Monitor) internally, which is exactly how a lock is implemented, giving you the same guarantees.

    0 讨论(0)
  • 2021-01-13 05:23

    The SemaphoreSlim guarantee is kind of implicit. It's described as a locking synchronization primitive in Overview of Synchronization Primitives.

    0 讨论(0)
提交回复
热议问题