gpt4 book ai didi

c++ - 带有 volatile 的多线程代码明显不安全行为的真实世界示例

转载 作者:太空狗 更新时间:2023-10-29 20:23:37 26 4
gpt4 key购买 nike

我读过很多answersarticles说明为什么 volatile 不能使多线程 C++ 代码安全。

我理解推理,我想理解可能的危险,我的问题是我无法创建或找到任何示例代码或提及使用它进行同步的程序产生实际可见的错误或意外行为的情况。我什至不需要它是可重现的(因为即使进行了优化,当前的编译器似乎也在尝试生成安全代码),只是一个真实发生的例子。

最佳答案

假设你有一个计数器,你想用它来跟踪某个操作完成了多少次,每次递增计数器。

如果你在多线程中运行这个操作,那么除非计数器是 std::atomic或者用锁保护那么你会得到意想不到的结果,volatile不会有帮助。

这是一个重现不可预知结果的简化示例,至少对我而言:

#include <future>
#include <iostream>
#include <atomic>

volatile int counter{0};
//std::atomic<int> counter{0};

int main() {
auto task = []{
for(int i = 0; i != 1'000'000; ++i) {
// do some operation...
++counter;
}
};
auto future1 = std::async(std::launch::async, task);
auto future2 = std::async(std::launch::async, task);
future1.get();
future2.get();
std::cout << counter << "\n";
}

Live demo .

这里我们使用 std::async 开始两个任务使用 std::launch::async启动策略以强制它异步启动。每个任务只是将计数器递增一百万次。两项任务完成后,我们预计计数器为 200 万。

但是,增量是读取计数器和写入计数器之间的读写操作,另一个线程可能也写入了它,增量可能会丢失。从理论上讲,因为我们已经进入了未定义行为的领域,所以绝对有可能发生任何事情!

如果我们将计数器更改为 std::atomic<int>我们得到了我们期望的行为。

此外,假设另一个线程正在使用 counter检测操作是否已经完成。不幸的是,没有什么能阻止编译器在它完成操作之前对代码重新排序并递增计数器。。同样,这可以通过使用 std::atomic<int> 来解决。或设置必要的内存栅栏。

参见 Effective Modern C++由 Scott Meyers 提供更多信息。

关于c++ - 带有 volatile 的多线程代码明显不安全行为的真实世界示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32035879/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com