【问题标题】:Making code thread safe without using the lock statement在不使用 lock 语句的情况下使代码线程安全
【发布时间】:2017-05-16 10:13:33
【问题描述】:

我想从多个线程调用以下代码。

// x is a global/member and initialized to 0
if (Interlocked.Increment(ref x) == 2)
{
   // do something only once
}

这当然不是线程安全的:如果在运行时第一个线程在 x 递增之后但在评估之前停止,然后第二个线程递增 x 所以它现在是 2,然后是 @987654324 @ 声明是true。然后我们回到第一个线程,它在if 语句中也成立。

这可以通过用lock 语句包围代码来解决。

有没有办法在不使用lock 语句的情况下使其线程安全?

【问题讨论】:

  • 你描述的场景不会发生,因为Interlocked.Increment()方法的返回值不能被其他线程改变。
  • 您的代码可能不安全,如果它稍后再次访问x 并假设它与增量的结果相同,但您没有在此处显示演示代码这个问题。

标签: c# multithreading thread-safety locking


【解决方案1】:

这当然不是线程安全的,因为如果在运行时第一个线程在 x 增加之后但在评估之前停止。然后第二个线程递增,x 知道 2,所以 if 语句为真。然后我们返回第一个线程,它也知道为真。

这不是真的。

Interlocked.Increment 是一个原子操作,不需要额外的lock。 (否则那有什么意义呢?)

该值正在递增,您将获得递增的值。即使随后发生了另一个增量,您仍然拥有第一个增量值。所以 if 将评估为 false。

您的代码是线程安全的。

【讨论】:

    【解决方案2】:

    我认为你的假设是不正确的。 Interlocked.Increment 的返回值是递增后的值,而不是评估时x 的值。 x 完全有可能已被另一个线程更改,因此以下情况为真:

    int x = 1;
    var y = Interlocked.Increment(ref x);
    
    if(x!=y)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-02
      • 2013-04-06
      • 2018-06-16
      相关资源
      最近更新 更多