信号量会阻止指令重新排序吗?

时间:2016-12-05 17:15:02

标签: c# .net multithreading locking semaphore

我在C#中寻找等待锁定语句的等价物。有些人建议以下列方式使用二进制SemaphoreSlim

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

我知道它有一些问题(例如它不可重入),但我最关心的是指令重新排序。

在普通的旧锁定语句中,我们保证不会将来自锁的内部指令移出锁定语句之外(之前或之后)。这个信号量解决方案是否同样适用?据我所见,documentation没有提到这个问题。

3 个答案:

答案 0 :(得分:1)

SemaphoreSlim以及几乎所有其他同步构造都是在内部使用Monitor(或构建在Monitor之上的其他类型)构建的,这正是如何实施lock,为您提供相同的保证。

答案 1 :(得分:0)

SemaphoreSlim保证是隐含的。它被描述为Overview of Synchronization Primitives中的锁定同步原语。

答案 2 :(得分:0)

我不是记忆模型的专家,但现在我认为我们有这些保证。

作为Servy has pointed outWaitRelease方法都使用了Monitor。但是,Monitor就是Wait

Monitor.Exit方法结束时,就在if (lockTaken) { m_waitCount--; //m_waitCount is volatile Monitor.Exit(m_lockObj); } 调用之前,一个volatile字段会递减。

Release

据我所知,在volatile字段上使用的递减运算符将引入'acquire'和'release'操作,阻止以下指令在它之前重新排序。

对于lock (m_lockObj) { //m_currentCount is volatile if (m_maxCount - m_currentCount < releaseCount) { throw new SemaphoreFullException(); } m_currentCount += releaseCount; 方法,情况类似。开始时我们同时拥有锁定获取和易失性读写操作。

SemaphoreSlim

特别感谢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() 中易变字段的重要性。

编辑:演示自身锁定(没有额外的易失操作)可能不够的情况的示例。

(2)

当尚未获取信号量时,来自关键部分(1)的读取指令可以重新排序到GC_CALLTYPE(另一个线程可能仍在关键部分中工作)。