执行信号量防止指令重新排序



我正在寻找等同于c#中的锁定语句。有些人建议使用以下方式使用二进制SemaphoreSlim

await semaphore.WaitAsync().ConfigureAwait(false);
try
{
    //inner instructions
}
finally
{
    semaphore.Release();
}

我知道它有一些问题(例如,这不是再入侵),但是我最大的担心是指令重新定序。

在普通的旧锁定语句中,我们可以保证不会在锁定语句(之前或之后)移出锁的内部指令。这个信号量解决方案是否同样存在?据我所知,该文档没有提及此问题。

SemaphoreSlim,几乎所有其他同步结构都是使用Monitor(或内部构建在Monitor顶部)的CC_3构建的,这恰恰是lock的方式实施,为您提供相同的保证。

SemaphoreSlim保证是隐式的。它被描述为同步原始概述中的锁定同步原始。

我不是内存模型的专家,但是现在我认为我们有保证。

正如Servy所指出的那样,WaitRelease方法都在引擎盖下使用Monitor。但是,Monitor本身可能还不够。

Wait方法的末尾,就在Monitor.Exit调用之前,降低了一个挥发性字段。

if (lockTaken)
{ 
    m_waitCount--; //m_waitCount is volatile
    Monitor.Exit(m_lockObj); 
} 
据我所知,挥发性字段上使用的减少操作员将引入"获取"one_answers"发行"操作,从而阻止以下说明在其之前重新排序。

至于Release方法,情况类似。一开始,我们同时进行了锁定和挥发性读写操作。

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

特别感谢Joe Duffy指出了SemaphoreSlim中挥发性领域的重要性。

edit :一个示例,说明锁定锁(没有其他挥发性操作)可能不够的情况。

// 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()

当尚未获取信号量时,可以将关键部分(2)的读取指令重新排序(另一个线程可能仍在关键部分中使用)。

最新更新