【问题标题】:Mutual exclusion: is this safe?互斥:这样安全吗?
【发布时间】:2009-02-16 14:36:43
【问题描述】:

这种互斥模式是否像我认为的那样安全?如果是这样,你怎么称呼它?

lock (_lock) {
    if (_flag) return;
    else _flag = true;
}
try {
    //critical code...
}
finally {
    _flag = false;
}

我想确保临界区,但没有其他线程堆积等待获取锁。显然,我确保标志没有设置在其他任何地方。有没有更好的办法?

【问题讨论】:

    标签: c# .net multithreading mutual-exclusion


    【解决方案1】:

    不,这不安全。如果要保证互斥不阻塞,可以使用Monitor.TryEnter:

    if (Monitor.TryEnter(lockObj, 0)) {
        // got the lock !
        try {
            // code
        }
        finally { // release the lock
            Monitor.Exit(lockObj);
        }
    }
    

    【讨论】:

    • 没关系,我会使用 TryEnter,但是你能解释一下上面的不安全吗?谢谢。
    • 好吧,您正在访问锁之外的标志。碰巧的是,您只是将其设置为 false,但这意味着您可能会拒绝一个基本线程 - 我可以预见问题。由于使用 TryEnter 相对容易,所以我会使用它...
    【解决方案2】:

    你看过Monitor.TryEnter吗?

    【讨论】:

      【解决方案3】:

      互斥模式的正确性取决于赋值 _flag=false 是原子的。想象一下如果分配可能被另一个线程中断会发生什么。如果分配的中间结果可能被测试解释为假,则一个分配可能导致多个线程进入临界区。

      互斥模式的正确性还取决于编译器中是否缺少可能重新排列语句顺序的优化。想象一个“智能”编译器,它会将赋值 _flag=false 向上移动,因为 _flag 在中间的代码中没有被引用(并且中间的代码不会抛出异常)。然后编译器可以优化锁定部分中的部分以读取

      if(_flag) return;
      

      模式失败的两个例子都是高度推测性的,我认为你可以安全地假设它有效。但是,如果存在另一个可以根据需要工作的选项,您最好使用它(请参阅其他帖子)。如果同一代码中有其他开发人员,则无需考虑该模式是否有效。

      【讨论】:

      • 有趣的答案,谢谢!我没有考虑优化的影响。
      【解决方案4】:

      一个简单的lock(Object) 语句不起作用吗?在幕后,它会在 try... finally 块内创建 Monitor 和临界区。

      private static readonly Object lockMe = new Object();
      lock(lockMe)
      {
          // critical code
      }
      

      【讨论】:

      • "但没有其他线程堆积等待获取锁。" - 即 OP 希望它互斥但非阻塞。
      • 这是一个有趣的要求。我从来不需要这样的锁定机制。
      猜你喜欢
      • 2013-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-14
      • 1970-01-01
      • 2012-06-05
      • 1970-01-01
      相关资源
      最近更新 更多