【发布时间】:2016-11-17 12:10:53
【问题描述】:
我想知道这是否是线程安全的,或者(如果不是)我如何使其安全。它从计时器中调用:
private volatile bool _isSynchronizing;
private void SynchronizeSessionCache(object state = null)
{
if (_isSynchronizing)
{
Log.Warn($"Aborted synchronization of SessionCache with SessionManager because we are already synchronizing. Interval is: {SynchronizationInterval}");
return;
}
_isSynchronizing = true;
bool lockWasTaken = false;
try
{
// some code that doesn't need a lock ...
// ...
// lock this part
Monitor.Enter(_lockObject, ref lockWasTaken);
// main code ...
}
finally // omitted catch
{
_isSynchronizing = false;
if(lockWasTaken)
Monitor.Exit(_lockObject);
}
}
我担心的是,一个线程可能会在他的方法开始时检查_isSynchronizing,而此时它是false。然后另一个线程进入主体,因为它还没有被thread1设置为true。即使_isSynchronizing 是volatile,这可能吗?如果是这样,使此方法线程安全的最佳方法是什么?
如果我理解正确volatile 不能防止这种竞争条件,只能确保变量没有被缓存,所以所有线程总是读取当前值。
【问题讨论】:
-
是的,两个胎面都有可能通过第一次检查。但是在方法内部你有一个锁,所以你希望多个线程进入,那是什么想法?
-
@Evk:我不希望有多个线程进入。
_lockObject也用于其他需要访问共享资源的方法和事件。这必须在同步期间锁定。绝不应该发生多个线程同时进入的情况。这就是我使用_isSynchronizing标志的原因。 -
那么我就在这里使用双重检查锁定。
-
将
_isSynchronizing设为int,然后写入if (Interlocked.CompareExchange(ref _isSynchronizing, 1, 0) != 0)。没有锁就解决了问题。 -
volatile 确保始终在 C# 中读取最新值的想法是错误的,所以不要相信它。 C# 规范仔细描述了 volatile 的实际含义,即写入 volatile 变量的效果如何相对于其他读取和写入重新排序是有限制的。正如我多次说过的,你应该阅读这篇文章,看看你是否理解如何重新排序易失性访问:blog.coverity.com/2014/03/26/reordering-optimizations
标签: c# .net multithreading locking