c# - 当我在两个连续的语句中读/写它时,我需要锁定一个 bool 值吗?

标签 c# .net multithreading locking

我想知道这是否是线程安全的,或者(如果不是)我如何使它安全。它是从计时器调用的:

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。然后另一个线程进入主体,因为它尚未被线程 1 设置为 true。即使 _isSynchronizingvolatile ,这也可能吗?如果是这样,使此方法线程安全的最佳方法是什么?

如果我理解正确 volatile 不能防止这种竞争条件,但只能确保变量没有被缓存,所以所有线程总是读取当前值。

最佳答案

为保证线程安全,您必须将比较和分配到单个原子操作。否则,当第一个线程正在执行分配时,另一个线程总是有可能通过比较。 volatile 关键字在这里没有帮助,因为它只是告诉编译器(和运行时)不允许优化,这可能会改变这个变量所涉及的读写操作的顺序。

(有关 volatile 的更多信息,您可以在 Eric Lippert 的 this 精彩文章中阅读。)

简单(稍微慢一点)的解决方案是围绕比较和分配设置一个临界区:

lock (_someLockObject)
{
    if (_isSynchronizing)
    {
         return;
    }

   _isSynchronizing = true;    
}

然而,有一个更快的解决方案,但不适用于 bool 变量。对于 int ,您可以使用 Interlocked.CompareExchange() 方法。

让我们假设 int _isSynchronizing = 0 表示 false_isSynchronizing = 1 表示 true

然后你可以使用这个语句:
if (Interlocked.CompareExchange(ref _isSynchronizing, 1, 0) == 1)
{
    // If the original val == 1, we're already synchronizing
    return;
}

这比使用 Monitor 稍快,但没有 bool 重载。

关于c# - 当我在两个连续的语句中读/写它时,我需要锁定一个 bool 值吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40654546/

相关文章:

c# - 继承真的隐藏了方法吗?

c# - C# 中的正则表达式

c# - 是否有 gtk# 应用程序的自动化框架?

java - 线程转储中的 "Locked ownable synchronizers"是什么?

c# - 如何以 List<T> 作为参数从泛型方法中读取值

c# - 执行阅读器 : Connection property has not been initialized

c# - EF 4.0 - 加载导航属性的导航属性

.net - 如何强制 Powershell 脚本等待覆盖文件,直到另一个进程完成读取该文件?

C# 事件和线程安全

c++ - STL 算法是否使用多核?