【问题标题】:Benign data race condition with two threads具有两个线程的良性数据竞争条件
【发布时间】:2012-11-17 12:57:13
【问题描述】:

这是竞争条件吗?

class A {
   int x; 

   update() {
      x = 5; 
   }

   retrieve() {
      y = x; 
   }
}

如果 update() 和 retrieve() 由两个不同的线程调用而没有持有任何锁,假设在共享变量的两次访问中至少有一次写入,这可以归类为竞争条件。但这真的是运行时的问题吗?

【问题讨论】:

  • 什么语言?还是一个与语言无关的问题?
  • 称这样的粗暴种族为“良性”就像称老虎为大猫一样。

标签: multithreading race-condition


【解决方案1】:

没有锁,可能会发生三件事:

  1. y 获取 x (5) 的新值。
  2. y 获取 x 的旧值(很可能是 0)。
  3. 如果写入int 不是原子的,那么y 可以获得任何其他值。

在 Java 中,对 int 的读取是原子的,因此第三个选项不会发生。不保证其他语言的原子性。

使用锁定,前两个选项也可以发生。

不过,根据内存模型的不同,还有一个额外的挑战。在 Java 中,如果写入未同步,则可以任意延迟到下一个同步点(synchronized 块的结尾或对volatile 字段的访问)。类似地,可以从前一个同步点(synchronized 块的开始或对volatile 字段的访问)任意缓存读取。这很容易导致陈旧缓存引起的问题。最终结果是,即使第一个选项应该发生,第二个选项也可能发生。

在 Java 中,始终将 volatile 与可从其他线程访问的字段一起使用,否则您将面临因内存访问重新排序而导致的难以调试的竞争条件。同样的警告也适用于使用类似于 Java 中的内存模型的其他语言 - 您可能需要告诉编译器不要进行这些优化。

【讨论】:

  • 在 C++ 中,volatile 不保证任何类型的同步或内存屏障。它所做的只是阻止某些类型的优化。我听说 VC++ 无缘无故地创建了一个内存屏障,但这不是标准的。
  • @JiveDadson 那么它实际上并不等同于 Java 的 volatile。重写。
  • @JiveDadson 另外,如果 volatile 关键字没有削减它,那么我不知道会发生什么。 Microsoft 编译器确实保证了这一点:msdn.microsoft.com/en-us/library/12a04hfd(v=vs.80).aspx
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-12
  • 2021-08-28
  • 2021-06-04
  • 2023-01-30
  • 1970-01-01
相关资源
最近更新 更多