.net 使用Interlocked.CompareExchange的以下示例是否需要易失性和/或内存屏障?
请注意:.net 使用Interlocked.CompareExchange的以下示例是否需要易失性和/或内存屏障?,.net,multithreading,.net,Multithreading,请注意: private DateTime m_lastTimeUtc; private int m_isInProgress; ... if (DateTime.UtcNow - m_lastTimeUtc >= m_interval) { if (Interlocked.CompareExchange(ref m_isInProgress, 1, 0) == 0) { if (DateTime.UtcNow - m_lastTimeUtc >= m
private DateTime m_lastTimeUtc;
private int m_isInProgress;
...
if (DateTime.UtcNow - m_lastTimeUtc >= m_interval)
{
if (Interlocked.CompareExchange(ref m_isInProgress, 1, 0) == 0)
{
if (DateTime.UtcNow - m_lastTimeUtc >= m_interval)
{
m_lastTimeUtc = DateTime.UtcNow;
// Do the work
m_lastTimeUtc = DateTime.UtcNow;
Interlocked.Exchange(ref m_isInProgress, 0);
}
}
}
此代码的预期语义如下所示:
- 代码可能会被频繁调用——每秒数百次
- 它应该或多或少地定期做某些工作。如果代码没有被频繁调用,那么实际的周期可能非常不规则,这是正常的。但是如果经常调用它(通常是这样),那么工作就会非常有规律地完成
- 点击
的线程将跳过该工作,这是完全正常的m_isInProgress=1
volatile
关键字和/或调用Interlocked.MemoryBarrier()
。如果我说我了解它们的工作原理,那我就是在撒谎
有人能解释一下我的代码中是否需要它们以及为什么吗
附言
我在几个地方重复了同样的模式。因此,我想介绍以下方法:
private static void DoWork(TimeSpan interval, ref DateTime lastTimeUtc, ref int isInProgress, Action work)
{
if (DateTime.UtcNow - lastTimeUtc >= interval && Interlocked.CompareExchange(ref isInProgress, 1, 0) == 0 && DateTime.UtcNow - lastTimeUtc >= interval)
{
lastTimeUtc = DateTime.UtcNow;
work();
lastTimeUtc = DateTime.UtcNow;
Interlocked.Exchange(ref isInProgress, 0);
}
}
鉴于此方法,我打算这样调用它:
DoWork(m_interval, ref m_lastTimeUtc, ref m_isInProgress, () =>
{
// Do the work
});
对于
DoWork
,答案是否相同?否,您不需要使用volatile
或内存屏障,因为是互锁的。CompareExchange
方法隐式生成完整的围栏,这会阻止指令重新排序和变量缓存
我建议您阅读以下内容: