返回信息流下面的程序,为什么有时候会读到r1和r2都是1?明明按任何顺序交错执行都不能出现这种结果的,难道程序可以穿越到未来去读到未来的结果?
//不要简单地说“有data race的程序都是未定义行为,什么都可能发生”,尽管这是事实,data race在C语言里就是未定义行为,真的什么都可能发生,从什么也不发生到机器冒烟都可能。但起码给出一个“为什么会发生”的解释。
若不加说明,所有的例子都是C++11(新标准)。
#include <cstdio>
#include <thread>
int x = 0;
int y = 0;
void thr1() {
int r1 = x;
y = 1;
std::printf("r1 = %d\n", r1);
}
void thr2() {
int r2 = y;
x = 1;
std::printf("r2 = %d\n", r2);
}
int main(int argc, char *argv[]) {
std::thread t1(thr1);
std::thread t2(thr2);
t1.join();
t2.join();
return 0;
}
为了避免争议,解释一下:上述程序是错误的。原因是两个线程中,存在冲突(conflict)的内存访问:
1、读写冲突: r1=x 和 x=1
2、读写冲突: r2=y 和 y=1
而冲突的读和写又没有任何同步(加锁,或者使用原子内存操作),故它们之间不存在happen-before关系。没有happen-before关系的冲突访问就是data race。data race在C11和C++11语言中是未定义行为(undefined behaviour),编译器可以假设这种事情不会发生,但如果真的发生了,则允许产生任何后果,从什么也没发生到机器冒烟都是允许的。
这是一条镜像帖。来源:北邮人论坛 / cpp / #81371同步于 2014/8/7
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖
[多线程毁三观]1.穿越时空
nuanyangyang
2014/8/7镜像同步54 回复
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
【 在 FromMars 的大作中提到: 】
: 有没有可能是std::printf("r2 = %d\n", r2); 这句话执行的时间较长?
不是。和printf都没有关系,只是为了打印出来便于观看。其实r2,r1早就都是1了。
为啥我刚刚运行好多次,都没出现过都是1的情况==
【 在 nuanyangyang 的大作中提到: 】
: 不是。和printf都没有关系,只是为了打印出来便于观看。其实r2,r1早就都是1了。
还跟着个有关?我怎么觉得仅仅因为线程争取cpu时间先后顺序--
【 在 wangxiaobupt 的大作中提到: 】
: 我怎么没试出来都为1的
: 由于标准输出不是线程安全的 我打印出来的都是很混乱的 = =
:
跟这个没关 只是我在测试的时候 结果都是些混乱的东西 不过总有一个0一个1
【 在 FromMars 的大作中提到: 】
: 还跟着个有关?我怎么觉得仅仅因为线程争取cpu时间先后顺序--
怎么混乱发咧?
我的运行结果一直是先0后1
等大神出解释,学习好了==
【 在 wangxiaobupt 的大作中提到: 】
: 跟这个没关 只是我在测试的时候 结果都是些混乱的东西 不过总有一个0一个1
:
乱序执行了吧?关掉优化试试
【 在 nuanyangyang 的大作中提到: 】
: 下面的程序,为什么有时候会读到r1和r2都是1?明明按任何顺序交错执行都不能出现这种结果的,难道程序可以穿越到未来去读到未来的结果?
: //不要简单地说“有data race的程序都是未定行为,什么都可能发生”,尽管这是事实,真的什么都可能发生,从什么也不发生到机器冒烟都可能。但起码给出一个“为什么会发生”的解释。
: 若不加说明,所有的例子都是C++11(新标准)。
: ...................