【发布时间】:2021-07-01 23:04:35
【问题描述】:
我有以下代码。我不明白为什么读者会看到不一致的变量值。
uint64_t get_counter() {
static uint64_t counter = 0;
static std::mutex m;
std::unique_lock l(m);
return ++counter;
}
auto main() -> int {
// uint64_t shared = 0;
std::atomic<uint64_t> shared = 0;
const auto writer = [&shared]() -> void {
while (true) {
shared = get_counter();
std::this_thread::yield();
}
};
const auto reader = [&shared]() -> void {
while (true) {
const uint64_t local = shared;
if (local > shared) {
cout << local << " " << shared << endl;
}
std::this_thread::yield();
}
};
std::thread w1(writer), w2(writer), r(reader);
r.join();
return EXIT_SUCCESS;
}
get_counter 只是生成严格递增数字的助手。实际上它可以被其他更有用的功能取代。
由于shared 永远不会变小,我希望在评估if (local > shared) 时,它永远不会是真的。但是,我得到这样的输出:
1022 1960
642677 644151
645309 645699
1510591 1512122
1592957 1593959
7964226 7965790
8918667 8919962
9094127 9095161
9116800 9117780
9214842 9215720
9539737 9541144
9737821 9739100
10222726 10223912
11197862 11199348
看起来local 确实比shared 小,但是为什么输出呢?它是由某些数据竞争引起的吗?如果是这样,如何在不引入互斥锁的情况下解决这个问题? std::atomic_thread_fence 可以用来帮忙吗? shared 必须是 std::atomic 吗?
【问题讨论】:
-
get_counter()返回的值应该是连续的,但不能保证它们会按顺序写入shared。您可以直接增加shared,这将给出顺序输出 -
有没有办法“直接增加
shared”而不将互斥锁放在主函数中,这是我想要避免的?get_counter中的互斥锁只是为了演示。 -
只是
shared++? -
您是否必须处理从
get_counter获得的每一个值?例如,如果 writer1 从get_counter获得 10,而 writer2 获得 8,但尝试在 writer1 之后写入,您是否仍想将 shared 设置为 8 还是可以放弃对get_counter的调用并重试(有效地跳过 8 你刚得到)? -
您知道
shared在if条件下的值和发送到cout的值可能不同吗?
标签: c++ multithreading atomic