自增不是原子操作,为什么这个代码没有表现出随机性?

wanghy1995 2020-04-03 01:35:13

#include <iostream>
#include <thread>

using namespace std;

void f(int *a) {
for(int i = 0; i < 100000; ++i) {
++*a;
}
}

int main() {
int a = 0;
thread t1(f, &a);
thread t2(f, &a);
t1.join();
t2.join();

cout << a << endl;
return 0;
}

运行了很多次全都是200000。gcc7.5
...全文
749 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
wanghy1995 2020-04-16
  • 打赏
  • 举报
回复
引用 15 楼 苏大强太强了 的回复:
这是咋回事? 求解?
按我的理解,有两个最重要的原因导致了这个现象: 1. 我测试这个机器是个单核CPU,所以不会存在两个线程同时运行的情况; 2. 要出现竞争条件,必须在一个线程对*a进行自增操作时发生线程切换,从结果看显然是我的机器调用f的过程中没有在++*a的间隙切换线程。(即使在f的循环体内加sleep也不能导致竞争,因为竞争条件必须要求在++*a语句执行的时候线程切换。)
苏大强太强了 2020-04-16
  • 打赏
  • 举报
回复
这是咋回事? 求解?
月凉西厢 2020-04-07
  • 打赏
  • 举报
回复
引用 8 楼 wanghy1995 的回复:
我明白了,我这个是单核机器,运行的时候为了效率很可能没有进行线程切换 !!
加个sleep看看?
wanghy1995 2020-04-07
  • 打赏
  • 举报
回复
我前面说的不对,不是不存在竞争条件,而是加sleep不能让竞争条件出现。自增有三步:访存,自增,写回。 比如*i = 0 线程A:读内存(0),在寄存器中自增为1,然后此时线程被切换,1的值入栈。 线程B:读内存(还是0),自增,写回(此时内存为1),此时线程再被切换 线程A:写回(寄存器中的1写入内存),此时内存值为1 上面过程虽然有两个线程对*i自增,但是最终效果只加了1次。 单核多线程程序仍然会出现竞争条件。至于加sleep的测试,在循环体内加sleep,线程在运行到sleep时已经自增完成(假设sleep加在++*a;语句后面),此时线程切换是不太可能会出现竞争的。 只有把sleep加到++*a这个缝隙中,才有可能看见竞争条件。
wanghy1995 2020-04-07
  • 打赏
  • 举报
回复
引用 12 楼 wanghy1995 的回复:
[quote=引用 11 楼 月凉西厢 的回复:] [quote=引用 8 楼 wanghy1995 的回复:] 我明白了,我这个是单核机器,运行的时候为了效率很可能没有进行线程切换 !!
加个sleep看看?[/quote] 我试了在循环体内加了sleep,没有用,结果还是20000。 也好理解,它是单核机器,不会出现两个线程同时读取,但写回到内存中只加1的情况。这里不可能出现竞争条件。 我用多核机器试了,几乎每次都是随机的[/quote] 也就是说就算有线程切换也不会影响结果,这次真明白了
wanghy1995 2020-04-07
  • 打赏
  • 举报
回复
引用 11 楼 月凉西厢 的回复:
[quote=引用 8 楼 wanghy1995 的回复:] 我明白了,我这个是单核机器,运行的时候为了效率很可能没有进行线程切换 !!
加个sleep看看?[/quote] 我试了在循环体内加了sleep,没有用,结果还是20000。 也好理解,它是单核机器,不会出现两个线程同时读取,但写回到内存中只加1的情况。这里不可能出现竞争条件。 我用多核机器试了,几乎每次都是随机的
wanghy1995 2020-04-06
  • 打赏
  • 举报
回复
引用 9 楼 yshuise 的回复:
传引用只能用std::ref()
这传的是个指针,不是引用
yshuise 2020-04-06
  • 打赏
  • 举报
回复
传引用只能用std::ref()
wanghy1995 2020-04-04
  • 打赏
  • 举报
回复
我明白了,我这个是单核机器,运行的时候为了效率很可能没有进行线程切换 !!
wanghy1995 2020-04-03
  • 打赏
  • 举报
回复
引用 6 楼 lin5161678 的回复:
你可以看看汇编 也许 这个循环被优化为 *a += 100000
汇编里它也是一次加1,见鬼了
lin5161678 2020-04-03
  • 打赏
  • 举报
回复
你可以看看汇编 也许 这个循环被优化为 *a += 100000
wanghy1995 2020-04-03
  • 打赏
  • 举报
回复
在winows机用的mingw gcc确实是随机的,linux上完全没变化
wanghy1995 2020-04-03
  • 打赏
  • 举报
回复
引用 2 楼 qybao 的回复:
我这边看的机器测试的结果也不是200000,随机的 但是觉得这个测不出原子性的吧,因为线程的栈内存回写到主线程内存信息也有干扰的。
我很想知道具体是什么原理, 因为我这里运行的很奇怪,重复运行1000次也没有一次例外。。
lin5161678 2020-04-03
  • 打赏
  • 举报
回复
引用 2 楼 qybao 的回复:
我这边看的机器测试的结果也不是200000,随机的 但是觉得这个测不出原子性的吧,因为线程的栈内存回写到主线程内存信息也有干扰的。
就是原子性的问题 写内存没分主线程子线程
qybao 2020-04-03
  • 打赏
  • 举报
回复
我这边看的机器测试的结果也不是200000,随机的
但是觉得这个测不出原子性的吧,因为线程的栈内存回写到主线程内存信息也有干扰的。
lin5161678 2020-04-03
  • 打赏
  • 举报
回复

64,648

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧