C++:std::atomic<bool> 和 volatile bool

标签 c++ multithreading

我正在阅读 Anthony Williams 的 C++ concurrency in action book。 这个经典的例子有两个线程,一个产生数据,另一个消耗数据,A.W.这段代码写得很清楚:

std::vector<int> data;
std::atomic<bool> data_ready(false);

void reader_thread()
{
    while(!data_ready.load())
    {
        std::this_thread::sleep(std::milliseconds(1));
    }
    std::cout << "The answer=" << data[0] << "\n";
}

void writer_thread()
{
    data.push_back(42);
    data_ready = true;
}

而且我真的不明白为什么这段代码与我使用经典的 volatile bool 而不是原子的不同。 如果有人能在这个问题上打开我的思路,我将不胜感激。 谢谢。

最佳答案

“经典”bool ,正如你所说,它不能可靠地工作(如果有的话)。造成这种情况的一个原因是编译器可以(并且很可能会,至少在启用优化的情况下)加载 data_ready只有一次来自内存,因为没有迹象表明它会在 reader_thread 的上下文中发生变化.

您可以使用 volatile bool 来解决这个问题。每次都强制加载它(这可能看起来可行),但这仍然是关于 C++ 标准的未定义行为,因为对变量的访问既不是同步的也不是原子的。

您可以使用 mutex header 中的锁定工具强制同步。 ,但这会引入(在您的示例中)不必要的开销(因此 std::atomic )。


volatile 的问题是它只保证不遗漏指令并保留指令顺序。 volatile 保证使用内存屏障来强制缓存一致性。这意味着 writer_thread在处理器 A 上,无需 reader_thread 就可以将值写入它的缓存(甚至可能写入主内存)在处理器 B 上看到它,因为处理器 B 的缓存与处理器 A 的缓存不一致。更详尽的解释见 memory barriercache coherence在维基百科上。


x = y 更复杂的表达式可能会出现其他问题(即 x += y )需要通过锁(或在这种简单的情况下为原子 += )进行同步以确保 x 的值在处理过程中不会改变。

x += y例如实际上是:

  • 阅读 x
  • 计算 x + y
  • 将结果写回 x

如果在计算期间发生上下文切换到另一个线程,这可能会导致类似这样的结果(2 个线程,都在执行 x += 2 ;假设 x = 0):

Thread A                 Thread B
------------------------ ------------------------
read x (0)
compute x (0) + 2
                 <context switch>
                         read x (0)
                         compute x (0) + 2
                         write x (2)
                 <context switch>
write x (2)

现在 x = 2即使有两个 += 2计算。这种效果被称为撕裂

关于C++:std::atomic<bool> 和 volatile bool,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29633222/

相关文章:

c++ - move 语义 : invalid conversion from `type&&` to `type` . 模板:将未知参数传递给重载函数

c++ - OpenGL 纹理分色

c++ - 字符串以某个字符串开头

c++ - 递归:基本情况与小版本

c++ - 概要分析:一行简单代码的 self 时间与总时间

java - 多线程应用程序随着线程数量的增加而增加运行时间

c++ - C++ 中并行 vector 的 find_first

java - Kafka : Single consumer group, 无分区和多个主题

c++ - 与模板函数一起使用时没有模板结构的隐式转换

java - Android 异步任务回收位图