我正在寻找等同于c#中的锁定语句。有些人建议使用以下方式使用二进制SemaphoreSlim
:
await semaphore.WaitAsync().ConfigureAwait(false);
try
{
//inner instructions
}
finally
{
semaphore.Release();
}
我知道它有一些问题(例如,这不是再入侵),但是我最大的担心是指令重新定序。
在普通的旧锁定语句中,我们可以保证不会在锁定语句(之前或之后)移出锁的内部指令。这个信号量解决方案是否同样存在?据我所知,该文档没有提及此问题。
SemaphoreSlim
,几乎所有其他同步结构都是使用Monitor
(或内部构建在Monitor
顶部)的CC_3构建的,这恰恰是lock
的方式实施,为您提供相同的保证。
SemaphoreSlim
保证是隐式的。它被描述为同步原始概述中的锁定同步原始。
我不是内存模型的专家,但是现在我认为我们有保证。
正如Servy所指出的那样,Wait
和Release
方法都在引擎盖下使用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)
的读取指令重新排序(另一个线程可能仍在关键部分中使用)。