【问题标题】:Threads read/writing at the same time线程同时读/写
【发布时间】:2012-05-20 23:27:41
【问题描述】:

如果我不在乎Thread1是否同时Flag1更改Thread2更改Flag1,除了逻辑错误还有什么需要担心的吗?如果出现以下情况,是否会导致崩溃等:

  1. Thread1Thread2 是否同时读取 Flag1
  2. Thread1 正在写入 Flag1,同时 Thread2 正在读取 Flag1

在这些示例中,Flag1bool

【问题讨论】:

  • 您可能需要仔细考虑“完全相同的时间”的真正含义以及这些操作如何在数字设备上发生。
  • 除非标志是对象的属性,否则它们本身都不会发生崩溃,可能不会被实例化。但是您可能会错过状态更改,或者在两个线程中检测到相同的更改。所以会发生什么取决于状态的变化。使其线程安全比试图应对它不安全的后果要容易得多
  • "除了逻辑错误" 既然你不关心程序逻辑,为什么还要费心呢?一个更简单的程序是“hello world”。它可能不会做你想做的事情,但是当你不关心逻辑错误时......
  • 值得提醒的是,虽然你不能同时读写一个bool变量,但是你可以同时读写一个“数据结构”,就像读vector[0]一样写信给vector[1] 就可以了。关键是你不能同时读取和写入原子数据类型。

标签: c++ multithreading


【解决方案1】:

根据C++11内存模型的规则:

  1. Thread1 和 Thread2 同时读取 Flag1? 这总是安全的。
  2. 线程 1 在读取标志 1 的同时写入标志 1? 这是数据竞争。

数据竞争是未定义的行为。虽然它不太可能在任何健全的硬件上崩溃,但它是未定义的行为,所以任何事情都可能发生。

【讨论】:

  • C++03 没有提到线程,所以不能保证 anything 完全可以工作。 C++11 提供了编译器和硬件供应商同意的保证,并且主要代表了现有实践的形式化。对于什么是有保证的,什么不是,你有更好的来源吗?我不会,所以只能从C++11内存模型的角度来回答。
  • @EitanT:问题被标记为“c++ 多线程”。 C++03 中没有“线程”的概念,因此推断这一定是 C++11,而 Jonathan 的答案是迄今为止唯一正确的答案。如果提问者想了解一些特定于平台的线程模型,他需要识别平台。
  • 那么您对 ​​C++ 中数据竞争的语义有更好的参考吗?
  • @EitanT,不,这不是无关紧要的,因为 C++11 内存模型在很多方面都是对现有实践的正式定义。您是否知道任何计划现在或将来实现不同内存模型的编译器?如果没有,那么建议人们遵守这些规则肯定是明智的。
  • @SvinSimpe 如果任何一个线程写入共享变量,则没有其他线程可以同时读取它。只有并发读取是可以的。
【解决方案2】:

据我所知,2 个线程不能同时访问同一个内存。

即使在并行计算中,这些假设也会由处理器自动处理。 http://en.wikipedia.org/wiki/Parallel_Random_Access_Machine

所以答案是没有崩溃。 您当然会遇到逻辑错误,但因为您不在乎:p。

【讨论】:

  • 2个线程不能同时访问同一个内存。”那么共享内存呢?
  • 时钟时间中的同一时间含义。他们实际上是轮流访问内存。
  • 我明白你现在的意思了,但我想说你的措辞有些误导​​。
  • 我想说,在最简单的模型中(我相信 OP 指的是),可以说两个线程同时运行,但从技术上讲,它们不是。因此,不可能同时物理访问同一地址。
  • 但是,如果在线程切换操作之前读/写操作未完成,则操作系统/硬件可能会锁定资源(并可能向其他访问线程引发错误) )。一般来说,这将由 CPU/驱动程序/操作系统自动处理,但要正确回答,我们必须了解有关操作系统、平台和硬件类型的更多详细信息。
【解决方案3】:

该标志应标记为volatile。这将确保您的编译器不会以不一致的方式优化读/写。

我相信对 bool 的读/写是原子性的——所以如果你不关心访问顺序,我认为你不会有任何其他问题。

【讨论】:

  • 不,volatile 与线程无关,不,对 bool 的访问通常不能保证是原子的(某些硬件可能会提供更强的保证,但这不是可移植的。)虽然 volatile将阻止编译器重新排序读取和写入它不会阻止硬件重新排序它们。使用原子类型或原子操作来获得正确的语义。
  • @JonathanWakely 嗯.. 对不起,我不明白 - 为什么你说 volatile 与线程无关?
  • @JonathanWakely - 他不在乎重新订购
  • 那么为什么建议使用 volatile 呢?跟线程无关,见hpl.hp.com/personal/Hans_Boehm/c++mm/user-faq.html
  • @JonathanWakely 我特别提到 volatile 是为了防止编译器进行优化。这是一个best effort 的建议。我们不希望编译器优化标志上的整个条件,对吗?显然,他不关心顺序 - 所以不需要使用 atomic。
猜你喜欢
  • 1970-01-01
  • 2021-11-04
  • 2014-11-29
  • 1970-01-01
  • 1970-01-01
  • 2011-11-19
  • 2020-08-17
  • 1970-01-01
  • 2018-11-14
相关资源
最近更新 更多