我一直在查看System.Reactive的源代码(此处),这把我带到了这个地方,其中有一个相同变量上的Volatile.Read
和Interlocked.CompareExchange
:
if (Volatile.Read(ref _runDrainOnce) == 0
&& Interlocked.CompareExchange(ref _runDrainOnce, 1, 0) == 0)
{
//do something
}
我的理解是,这个逻辑是“如果runDrainOnce为0,并且在我将其更改为1之前它也为0”。这里是否有什么微妙之处?为什么第一个检查不是多余的?
更令人费解的是,在同一个函数中存在lock和Monitor.Pulse。 这是赌注的结果吗? :))
整个函数:
private void Schedule()
{
// Schedule the suspending drain once
if (Volatile.Read(ref _runDrainOnce) == 0
&& Interlocked.CompareExchange(ref _runDrainOnce, 1, 0) == 0)
{
_drainTask.Disposable = _scheduler.ScheduleLongRunning(this, DrainLongRunning);
}
// Indicate more work is to be done by the drain loop
if (Interlocked.Increment(ref _wip) == 1L)
{
// resume the drain loop waiting on the guard
lock (_suspendGuard)
{
Monitor.Pulse(_suspendGuard);
}
}
}
Volatile.Read
使用半围栏(获取),而Interlocked.CompareExchange
则是全围栏(获取和释放)。看起来他们试图在_runDrainOnce
不为0的情况下避免使用全围栏。 - Sean