【发布时间】:2021-06-24 15:40:29
【问题描述】:
当我运行这个程序时,我得到的输出是 10,这对我来说似乎是不可能的。我在 x86_64 core i3 ubuntu 上运行它。
如果输出是 10,那么 1 肯定来自 c 或 d。
同样在线程 t[0] 中,我们将 c 赋值为 1。现在 a 为 1,因为它出现在 c=1 之前。 c 等于 b,线程 1 将其设置为 1。所以当我们存储 d 时,它应该是 1,因为 a=1。
- 输出 10 可以与 memory_order_seq_cst 一起发生吗?我尝试在第 1 行(变量 =1 )和第 2 行(printf)之间的两个线程上插入 atomic_thread_fence(seq_cst) 但它仍然没有工作。
取消注释 fence 不起作用。 尝试使用 g++ 和 clang++ 运行。两者都给出相同的结果。
#include<thread>
#include<unistd.h>
#include<cstdio>
#include<atomic>
using namespace std;
atomic<int> a,b,c,d;
void foo(){
a.store(1,memory_order_seq_cst);
// atomic_thread_fence(memory_order_seq_cst);
c.store(b,memory_order_seq_cst);
}
void bar(){
b.store(1,memory_order_seq_cst);
// atomic_thread_fence(memory_order_seq_cst);
d.store(a,memory_order_seq_cst);
}
int main(){
thread t[2];
t[0]=thread(foo); t[1]=thread(bar);
t[0].join();t[1].join();
printf("%d%d\n",c.load(memory_order_seq_cst),d.load(memory_order_seq_cst));
}
bash$ while [ true ]; do ./a.out | grep "10" ; done
10
10
10
10
【问题讨论】:
-
你调试/设置断点和单步吗?
-
@StureS 这是一个线程问题,设置断点和单步执行会改变程序的行为。
-
这应该会给你一个线索,问题出在哪里。请参阅下面 Dani 的答案。
-
@RichardCritten:公平地说,分别设置断点和单步执行每个线程可以让您探索可能的排序。但不是运行时 re 存储缓冲区和飞行中的多个请求的排序效果;单步执行非常慢,以至于在编译器确定了它选择的任何编译时顺序之后,每个 asm 操作实际上都是 seq_cst。对于无锁队列之类的设计进行健全性检查可能是一种有用的技术,但可能不适用于此类。 (虽然一切都已经是 seq_cst 所以也许)
-
@nvn:您的文字描述仍在讨论每个线程函数内部的 printfs,而不是在两个加入之后。如果您打印了
d=%d\n或其他任何方式,则任何一种方式都是等效的;这种方式确实可以明确哪个数字来自哪个变量。
标签: c++ multithreading memory-barriers stdatomic lockless