一、现象

先上源码:

#include <thread>
#include <iostream>
int main() {int a = 0;int flag = 0;std::thread t1([&]() {while (flag != 1);int b = a;std::cout << "b = " << b << std::endl;});std::thread t2([&]() {a = 5;flag = 1;});t1.join();t2.join();return 0;
}

-O0优化时,执行结果如下:

autosar@autosar-virtual-machine:~/test/study_C++$ g++ main.cpp -std=c++11 -pthread -O0 -g
autosar@autosar-virtual-machine:~/test/study_C++$ ./a.out
b = 5
autosar@autosar-virtual-machine:~/test/study_C++$

-O2优化时,执行结果如下:

autosar@autosar-virtual-machine:~/test/study_C++$ g++ main.cpp -std=c++11 -pthread -O2 -g
autosar@autosar-virtual-machine:~/test/study_C++$ ./a.out

二、解释

可以看到-O2优化之后,程序卡住不动了。gdb进去之后发现卡在了t1线程的while循环中。

反汇编之后,发现t1线程优化后,在while循环访问flag的时候,并不是每次都去内存里取flag的值,而是t1线程启动时从内存中读出一次flag的值到寄存器,然后每一次循环都把寄存器中的值拿出来与0x01比较。

(gdb) disass
Dump of assembler code for function std::thread::_Impl<std::_Bind_simple<main()::<lambda()>()> >::_M_run(void):
0x00000000004011d0 <+0>: mov 0x18(%rdi),%rax
0x00000000004011d4 <+4>: mov (%rax),%eax
0x00000000004011d6 <+6>: nopw %cs:0x0(%rax,%rax,1)
0x00000000004011e0 <+16>: cmp $0x1,%eax //这里直接读取eax寄存器,eax永远是0
0x00000000004011e3 <+19>: jne 0x4011e0 <std::thread::_Impl<std::_Bind_simple<main()::<lambda()>()> >::_M_run(void)+16> //这里跳转到+16行

然而在t2线程中,对flag赋值时,是向对应的内存地址写入1.

(gdb) disass
Dump of assembler code for function std::thread::_Impl<std::_Bind_simple<main()::<lambda()>()> >::_M_run(void):
0x0000000000401110 <+0>: mov 0x18(%rdi),%rax
0x0000000000401114 <+4>: movl $0x5,(%rax)
0x000000000040111a <+10>: mov 0x20(%rdi),%rax
0x000000000040111e <+14>: movl $0x1,(%rax) //向内存中写入0x01
0x0000000000401124 <+20>: retq
End of assembler dump.

所以t2线程对flag的修改无法影响到t1线程。

三、 解决办法

给flag变量加入volatile修饰词之后,问题得到解决。

autosar@autosar-virtual-machine:~/test/study_C++$ g++ main.cpp -std=c++11 -pthread -O2 -g
autosar@autosar-virtual-machine:~/test/study_C++$ ./a.out
b = 5
autosar@autosar-virtual-machine:~/test/study_C++$

加入volatile之后的反汇编如下:

(gdb) disass
Dump of assembler code for function std::thread::_Impl<std::_Bind_simple<main()::<lambda()>()> >::_M_run(void):
0x00000000004011d0 <+0>: mov 0x18(%rdi),%rdx
0x00000000004011d4 <+4>: nopl 0x0(%rax)
0x00000000004011d8 <+8>: mov (%rdx),%eax
0x00000000004011da <+10>: cmp $0x1,%eax
0x00000000004011dd <+13>: jne 0x4011d8 <std::thread::_Impl<std::_Bind_simple<main()::<lambda()>()> >::_M_run(void)+8> //跳转到+8行,即每次while都会从内存读取flag

可以看到,每一次while循环都会跳转到+8行,从内存读出flag值存到寄存器中。

O2优化后,程序freez了(变量的读取过程被优化,使用volatile可解决)相关推荐

  1. 服务器主板用360优化后崩溃,360极速浏览器使用时崩溃了怎么办-卡屏幕崩溃现象解决方法 - Iefans...

    360极速浏览器一款在保证安全和稳定的基础上可以让使用者进行极速阅读的浏览器,但有的时候会因为一些小问题在用户使用时会导致卡屏幕崩溃的现象出现,现在就和小编一起来瞅瞅这篇解决方案吧 360极速浏览器崩 ...

  2. 插件开发遇到的坑------final 型变量,编译过程被优化

    android 插件开发遇到的坑 今天遇到一个坑,pdf 插件,调用了主工程的一个静态final 字符串,但是主工程里面已经没有这个字符串了,却没有崩溃. 后来同事说,因为字符串可能已经直接被写死了. ...

  3. 使用运行时间分析工具SE30优化ABAP程序

    使用ABAP运行时间分析工具SE30优化程序 ABAP运行时间分析工具使用SE30方法 (一) 操作 (二) 分析方法 (三) 相关事物码 (四) 附:SQL语句优化方法(引用部分) ABAP运行时间 ...

  4. 润乾报表实现计算过程性能优化

    当报表出现性能问题,需要对数据源计算进行优化时,控制执行路径是一种有效的方法,但也是阻碍优化的难题.这是由于数据库执行路径不透明,程序员很难甚至无法干预执行路径,进而也就难以提高数据库访问的性能.而对 ...

  5. win10 系统,java安装后如何配置环境变量,解决“'javac' 不是内部或外部命令,也不是可运行的程序 或批处理文件。”问题

    相信每个新手装了java JDK,在文本编辑器上高高兴兴写了"HellloWorld"之后一定会遇到这种情况. 这是因为电脑没有进行环境变量设置而造成的问题 所以... 第一步右击 ...

  6. squid完全攻略(一)squid优化后详细安装步骤

    Squid工作原理 Squid是Linux下一个缓存Internet数据的代理服务器软件,它接收用户的下载申请并自动处理所下载的数据.即当一个用户下载www.idcshare的页面,他请求squid为 ...

  7. squid完全攻略 squid优化后详细安装步骤

    Squid工作原理 http://os.51cto.com/art/201009/225813.htm http://os.51cto.com/art/201009/223455.htm Squid是 ...

  8. arduino 休眠 节能_优化arduino程序存储空间

    0x00 Abstract 我们一般在开发Arduino的程序时都是根据功能需求来编写代码,当经过测试后程序满足功能需求后就停止开发,剩下的就是只有在功能需求变更或代码中存在bug时才会再次动手修改代 ...

  9. 详解优化iOS程序性能的25个方法

    本篇文章主要介绍了优化iOS程序性能的25个方法,感兴趣的小伙伴们可以参考一下 1. 用ARC管理内存 ARC(Automatic ReferenceCounting, 自动引用计数)和iOS5一起发 ...

最新文章

  1. 17. Letter Combinations of a Phone Number 电话号码的字母组合
  2. 常用的C#方法【Format.CS】
  3. bzoj 1626: [Usaco2007 Dec]Building Roads 修建道路(最小生成树)
  4. Iphone 开发常用代码
  5. Java开发支付宝支付功能
  6. 如何下载飞思卡尔单片机的S19文件
  7. IT书籍电子书下载网站
  8. 好歌推荐 绝对经典(中外结合)
  9. Axure R8学习记录
  10. unity3d 重力加速度传感器控制摄像头
  11. 网咖虚拟服务器主机,为什么网吧的主机这么便宜??但是玩大型游戏又不卡
  12. Ubuntu 卡住了怎么办
  13. 爱福窝在线装修设计软件测评
  14. Picasso源码初步分析
  15. 沈阳计算机专业中专学校有哪些,沈阳市都有哪些中专学校是公立的
  16. [console] early printk实现流程
  17. Javaweb 请求转发和请求重定向
  18. 百度网盘下载文件教程
  19. redhat系列镜像下载
  20. Java listFiles查找指定类型的文件简单做法

热门文章

  1. AHRS简要说明及使用例程(外加踩坑)
  2. Centos MySQL5.7开机自启动
  3. 生活小技巧 | win10开热点给手机使用
  4. 第43期ACM_ICPC亚洲区域赛(焦作站)感想
  5. python协程详解
  6. 无线蓝牙打印机服务器有什么用,蓝牙打印机价格怎么样 蓝牙打印机有什么用途...
  7. 从表征到行动---意向性的自然主义进路(续四)
  8. 求所有质因子(Java)
  9. 解决某些MySQL数据库的表没了,建数据库也建不了的情况
  10. python随机数种子seed()的讲解