C ++如果一个线程写入一旦完成就会切换一个布尔值,那么在另一个线程的循环中读取该布尔值是不是安全?

Posted

技术标签:

【中文标题】C ++如果一个线程写入一旦完成就会切换一个布尔值,那么在另一个线程的循环中读取该布尔值是不是安全?【英文标题】:C++ if one thread writes toggles a bool once done, is it safe to read that bool in a loop in a single other thread?C ++如果一个线程写入一旦完成就会切换一个布尔值,那么在另一个线程的循环中读取该布尔值是否安全? 【发布时间】:2016-12-18 20:23:29 【问题描述】:

我正在构建一个非常简单的程序作为练习。

这个想法是通过递归迭代其所有内容,并对目录(及其子目录)中包含的所有文件的大小求和来计算目录的总大小。

为了向用户显示程序仍在运行,此计算在另一个线程上执行,而主线程每秒打印一个点 .

现在主线程当然需要知道它什么时候应该停止打印点并且可以查找结果。 可以使用例如std::atomic<bool> done(false); 并将其传递给将执行计算的线程,一旦完成,它将设置为 true。但我想知道在这种简单的情况下(一个线程一旦完成写入,一个线程定期读取直到非零)是否有必要为此使用原子数据类型。显然,如果 多个 线程可能会对其进行写入,则需要对其进行保护。但是在这种情况下,只有一个写线程和一个读线程。

这里是否有必要使用原子数据类型,或者是否过度使用而可以使用普通数据类型来代替?

【问题讨论】:

【参考方案1】:

是的,这是必要的。

问题在于处理器的不同内核可能对“相同”数据有不同的看法,尤其是缓存在 CPU 中的数据。 atomic 部分可确保正确刷新这些缓存,以便您可以安全地做您想做的事情。

否则,其他线程很可能永远不会真正看到标志与第一个线程相比的变化。

【讨论】:

【参考方案2】:

是的,这是必要的。规则是,如果两个线程可能同时访问相同的内存,并且至少有一个线程是写入器,那么您就有了数据竞争。任何具有数据竞争的程序执行都有未定义的行为。

来自 C++14 标准的相关引用:

1.10/23

如果程序的执行包含两个潜在的并发冲突操作,则程序的执行包含数据竞争,其中至少一个不是原子的,并且两者都不会在另一个之前发生,除了下面描述的信号处理程序的特殊情况。任何此类数据竞争都会导致未定义的行为。

1.10/6

如果其中一个修改内存位置 (1.7) 而另一个访问或修改相同的内存位置,则两个表达式计算会发生冲突。

【讨论】:

我希望原始intbool 的写入/读取是原子的。为什么不是这样? (或者它是那些“不能假设”的事情之一?)无论如何,感谢您引用标准中的相关部分。这是迄今为止最明确的答案:-)。 @Qqwy:我相信创建原子对象的唯一标准方法是声明它的类型为std::atomic<T>std::atomic_flag【参考方案3】:

是的,这是必要的。否则,不能保证在一个线程中对bool 的更改将在另一个线程中可见。事实上,如果编译器发现bool 变量显然没有在设置它的执行线程中再次使用,它可能会完全优化设置bool 值的代码。

【讨论】:

如果布尔标记为volatile,则编译器无法优化任何访问。 哇。因此,即使我将 bool 作为对线程的引用,编译器也可能会将我的代码重写为永远不会看到值更改的代码? 如果编译器发现 bool 值在设置后不再被执行线程使用,编译器可以合法地优化整个事情。事实上,在较早的某个时间点,执行线程构造了一个名为std::thread 的类的实例,并将引用或指针传递给该布尔值并没有改变。 C++ 编译器不知道构造一个名为std::thread 的类的实例最终会创建一个新的执行线程这一事实。这是 C++ 库的一个功能。 @StoryTeller - 但这无济于事。 volatile 与线程无关,它与内存映射硬件有关。如果线程在不同的 CPU 上运行,它们可能看不到彼此的volatile 变量,即使读取和写入是由硬件执行的。使用原子他们可以。 @RonyTesler,有什么阻止您编写一些快速基准测试来衡量您的实际硬件/软件的差异吗?

以上是关于C ++如果一个线程写入一旦完成就会切换一个布尔值,那么在另一个线程的循环中读取该布尔值是不是安全?的主要内容,如果未能解决你的问题,请参考以下文章

在 write() 写入的字节数少于请求的字节数后,如何让线程继续?

windows环境,多线程情况下,C语言向文件写入数据。

c# 一个程序关闭,如果有前台线程还在运行,当前台线程运行完是不是会关闭?还是一直存在?

Java 多线程 相关概念

Java CAS 比较并且更换值

当两个锁定线程(通过变量),切换其中一个变量并尝试访问另一个变量时会发生什么?