volatile有好几个特性,让我们来验证一下

1.对声明为volatile的变量操作时,每次都会从内存中取值,而不会使用原先保存在寄存器中的值。

让我们看一下两个例子,一个例子是对不声明为volatile的变量操作,一个例子是对声明为volatile的变量操作。编译器为gcc version 4.8.4,平台为32位ubuntu14.04,开启了一级优化,即g++ -O1 -std=c++11。汇编部分只看有注释的部分就行了。

//非volatile版#include<stdio.h>
#include<pthread.h>
#include<iostream>
int fun(int a){int x;scanf("%d",&x);if(a > x)return a;else return x;
}
int main(){int a = 5;   //声明为非volatileint b = 10;int c = 20;int d;scanf("%d",&c);a = fun(c);b = a + 1;printf("%d,%d\n",b,d);return 0;;}080485fd <_Z3funi>:80485fd:  53                      push   %ebx80485fe: 83 ec 28                sub    $0x28,%esp8048601:   8b 5c 24 30             mov    0x30(%esp),%ebx8048605:  8d 44 24 1c             lea    0x1c(%esp),%eax8048609:  89 44 24 04             mov    %eax,0x4(%esp)804860d:   c7 04 24 50 87 04 08    movl   $0x8048750,(%esp)8048614:    e8 d7 fe ff ff          call   80484f0 <scanf@plt>8048619:   8b 44 24 1c             mov    0x1c(%esp),%eax804861d:  39 c3                   cmp    %eax,%ebx804861f:    0f 4d c3                cmovge %ebx,%eax8048622:    83 c4 28                add    $0x28,%esp8048625:   5b                      pop    %ebx8048626: c3                      ret    08048627 <main>:8048627:   55                      push   %ebp8048628: 89 e5                   mov    %esp,%ebp804862a:    83 e4 f0                and    $0xfffffff0,%esp804862d: 83 ec 20                sub    $0x20,%esp8048630:   c7 44 24 1c 14 00 00    movl   $0x14,0x1c(%esp)8048637: 00 8048638: 8d 44 24 1c             lea    0x1c(%esp),%eax804863c:  89 44 24 04             mov    %eax,0x4(%esp)8048640:   c7 04 24 50 87 04 08    movl   $0x8048750,(%esp)8048647:    e8 a4 fe ff ff          call   80484f0 <scanf@plt>804864c:   8b 44 24 1c             mov    0x1c(%esp),%eax8048650:  89 04 24                mov    %eax,(%esp)8048653:  e8 a5 ff ff ff          call   80485fd <_Z3funi> //调用fun函数,返回值保存在eax中8048658:  c7 44 24 0c 00 00 00    movl   $0x0,0xc(%esp)804865f:   00 8048660: 83 c0 01                add    $0x1,%eax  //直接使用eax中的值(b = a + 1)8048663: 89 44 24 08             mov    %eax,0x8(%esp)8048667:   c7 44 24 04 53 87 04    movl   $0x8048753,0x4(%esp)804866e: 08 804866f: c7 04 24 01 00 00 00    movl   $0x1,(%esp)8048676:  e8 35 fe ff ff          call   80484b0 <__printf_chk@plt>804867b:    b8 00 00 00 00          mov    $0x0,%eax8048680:    c9                      leave  8048681: c3                      ret    
//volatile版本#include<stdio.h>
#include<pthread.h>
#include<iostream>
int fun(int a){int x;scanf("%d",&x);if(a > x)return a;else return x;
}
int main(){volatile int a = 5;//声明为volatile int b = 10;int c = 20;int d;scanf("%d",&c);a = fun(c);b = a + 1;printf("%d,%d\n",b,d);return 0;;}080485fd <_Z3funi>:80485fd:    53                      push   %ebx80485fe: 83 ec 28                sub    $0x28,%esp8048601:   8b 5c 24 30             mov    0x30(%esp),%ebx8048605:  8d 44 24 1c             lea    0x1c(%esp),%eax8048609:  89 44 24 04             mov    %eax,0x4(%esp)804860d:   c7 04 24 60 87 04 08    movl   $0x8048760,(%esp)8048614:    e8 d7 fe ff ff          call   80484f0 <scanf@plt>8048619:   8b 44 24 1c             mov    0x1c(%esp),%eax804861d:  39 c3                   cmp    %eax,%ebx804861f:    0f 4d c3                cmovge %ebx,%eax8048622:    83 c4 28                add    $0x28,%esp8048625:   5b                      pop    %ebx8048626: c3                      ret    08048627 <main>:8048627:   55                      push   %ebp8048628: 89 e5                   mov    %esp,%ebp804862a:    83 e4 f0                and    $0xfffffff0,%esp804862d: 83 ec 20                sub    $0x20,%esp8048630:   c7 44 24 18 05 00 00    movl   $0x5,0x18(%esp)8048637:  00 8048638: c7 44 24 1c 14 00 00    movl   $0x14,0x1c(%esp)804863f: 00 8048640: 8d 44 24 1c             lea    0x1c(%esp),%eax8048644:  89 44 24 04             mov    %eax,0x4(%esp)8048648:   c7 04 24 60 87 04 08    movl   $0x8048760,(%esp)804864f:    e8 9c fe ff ff          call   80484f0 <scanf@plt>8048654:   8b 44 24 1c             mov    0x1c(%esp),%eax8048658:  89 04 24                mov    %eax,(%esp)804865b:  e8 9d ff ff ff          call   80485fd <_Z3funi>//调用fun函数8048660: 89 44 24 18             mov    %eax,0x18(%esp) //把返回值放入a对应的内存中8048664:  8b 44 24 18             mov    0x18(%esp),%eax //从a的内存中取值8048668:   c7 44 24 0c 00 00 00    movl   $0x0,0xc(%esp)804866f:   00 8048670: 83 c0 01                add    $0x1,%eax       //然后加1(b = a + 1)8048673:  89 44 24 08             mov    %eax,0x8(%esp)  8048677: c7 44 24 04 63 87 04    movl   $0x8048763,0x4(%esp)804867e: 08 804867f: c7 04 24 01 00 00 00    movl   $0x1,(%esp)8048686:  e8 25 fe ff ff          call   80484b0 <__printf_chk@plt>804868b:    b8 00 00 00 00          mov    $0x0,%eax8048690:    c9                      leave  8048691: c3                      ret    

2.编译器不会对声明为volatile的变量进行优化,比如说声明了一个变量但是没有使用或者是使用了但是程序不关心使用后的结果。如果是没有声明volatile的变量编译器会忽略掉这个变量,但是如果把这个变量声明为volatile,那么编译器就不可以忽略这个变量,看下面的例子。

#include<stdio.h>
#include<pthread.h>
#include<iostream>int main(){int a = 5;int b = 10;int c = 20;int d;a = b + 1;return 0;;}生成的汇编代码中把所有的变量都忽略了0804857d <main>:804857d: b8 00 00 00 00          mov    $0x0,%eax8048582:    c3                      ret

接下来让我们把a声明为volatile变量再看看会发生什么事情

#include<stdio.h>
#include<pthread.h>
#include<iostream>int main(){volatile int a = 5;int b = 10;int c = 20;int d;return 0;;}生成的汇编中并没有忽略变量a0804857d <main>:804857d:    83 ec 10                sub    $0x10,%esp8048580:   c7 44 24 0c 05 00 00    movl   $0x5,0xc(%esp)// a = 58048587:  00 8048588: b8 00 00 00 00          mov    $0x0,%eax804858d:    83 c4 10                add    $0x10,%esp8048590:   c3                      ret

3.顺序性(和java中的顺序性不太一样)

这里用的g++的2级优化int a;
int b;int fun(){a = b + 1;b = 0;return 0;
}080485c0 <_Z3funv>:80485c0:  a1 2c a0 04 08          mov    0x804a02c,%eax //取b的值80485c5:    c7 05 2c a0 04 08 00    movl   $0x0,0x804a02c // b = 080485cc: 00 00 00 80485cf:   83 c0 01                add    $0x1,%eax  // a = b + 180485d2:    a3 30 a0 04 08          mov    %eax,0x804a03080485d7:   31 c0                   xor    %eax,%eax80485d9:    c3                      ret    

由上面的例子可见编译器会对原来的程序重排顺序,再让我们把a声明为volatile看还会发生重排吗

这里用的g++的2级优化
volatile int a;
int b;int fun(){a = b + 1;b = 0;return 0;
}080485c0 <_Z3funv>:80485c0:  a1 2c a0 04 08          mov    0x804a02c,%eax //取b的值80485c5:    c7 05 2c a0 04 08 00    movl   $0x0,0x804a02c //b = 080485cc:  00 00 00 80485cf:   83 c0 01                add    $0x1,%eax    // a = b + 180485d2:  a3 30 a0 04 08          mov    %eax,0x804a03080485d7:   31 c0                   xor    %eax,%eax80485d9:    c3                      ret    

从上面的程序来看还是会发生指令重排,让我们再把两个变量都声明为volatile来看看。

这里用的g++的2级优化
volatile int a;
volatile int b;int fun(){a = b + 1;b = 0;return 0;
}080485c0 <_Z3funv>:80485c0:  a1 2c a0 04 08          mov    0x804a02c,%eax //取b的值80485c5:    83 c0 01                add    $0x1,%eax  // a = b+180485c8:  a3 30 a0 04 08          mov    %eax,0x804a030//把结果放入a中80485cd:  31 c0                   xor    %eax,%eax80485cf:    c7 05 2c a0 04 08 00    movl   $0x0,0x804a02c //b = 080485d6:  00 00 00 80485d9:   c3                      ret    

从上面结果来看,如果两个都声明为volatile,那么编译器就不会对指令进行重排

C++中volatile变量测试相关推荐

  1. vilatile 深入理解java虚拟机_《深入理解Java虚拟机》笔记 第十二章 volatile变量

    当一个变量定义成volatile之后,它将具备两种特性: 1.第一是保证此变量对所有线程的可见性,这里的"可见性"是指当一条线程修改了这个变量的值,新值对于其它线程是可以立即得知的 ...

  2. java中的Volatile 变量

    Java 语言中的 volatile 变量可以被看作是一种 "程度较轻的 synchronized":与 synchronized 块相比,volatile 变量所需的编码较少,并 ...

  3. java中的volatile变量

    同步与线程间通信: 通信  通信是指消息在两条线程之间传递.  既然要传递消息,那接收线程 和 发送线程之间必须要有个先后关系,此时就需要用到同步.通信和同步是相辅相成的. 同步  同步是指,控制多条 ...

  4. webdriver自动化测试工具的使用,将chromedriver配置到path环境变量中,并测试是否成功

    文章目录 webdriver概述 安装chrome webdriver 1. 查看自己的chrome谷歌浏览器版本 2. 去国内镜像地址下载对应浏览器版本的webdriver 3. 下载好之后解压,将 ...

  5. Java Volatile变量说明与测试

    Volatile 字段 Volatile 字段为实例字段的同步访问提供了一种免锁机制.如果声明一个字段为 volatile ,那么编译器和虚拟机就知道该字段可能被另一个线程并发更新. 编译器会插入适当 ...

  6. C/C++中volatile关键字详解

    1. 为什么用volatile? C/C++ 中的 volatile 关键字和 const 对应,用来修饰变量,通常用于建立语言级别的 memory barrier.这是 BS 在 "The ...

  7. Java 理论与实践: 正确使用 Volatile 变量--转

    原文地址:http://www.ibm.com/developerworks/cn/java/j-jtp06197.html Java 语言中的 volatile 变量可以被看作是一种 "程 ...

  8. java volatile 死锁_Java 多线程:volatile 变量、happens-before 关系及内存一致性

    原标题:Java 多线程:volatile 变量.happens-before 关系及内存一致性 来源:ImportNew - paddx 更新 请参考来自 Jean-philippe Bempel ...

  9. 从缓存行出发理解volatile变量、伪共享False sharing、disruptor

    volatile关键字 当变量被某个线程A修改值之后,其它线程比如B若读取此变量的话,立刻可以看到原来线程A修改后的值 注:普通变量与volatile变量的区别是volatile的特殊规则保证了新值能 ...

最新文章

  1. 大一c语言大作业课题大全,昆明理工大学大一C语言大作业题目.doc
  2. MCU实战经验:多种的按键处理
  3. n1进入recovery模式_启动自动变砖模式?三星Galaxy“智能”手机
  4. RecyclerView源码解析 - 分割线
  5. 解决oracle连接很慢问题
  6. QT Creator应用程序开发——信号与槽
  7. 网站运行怎么选服务器,wordpress外贸建站服务器怎么选
  8. 抽象工厂模式与单件模式C++混合实现
  9. Panda_Cloud_v1.2 源代码开源
  10. scrapy SpiderMiddleware DownloaderMiddleware
  11. 转:Mybatis与JDBC批量插入数据库哪个更快
  12. PS证件照排版计算器
  13. 偷偷看了同事的代码找到了优雅代码的秘密
  14. 如何制作运营高质量的竞价单页
  15. 嵌入式开发—串口通信
  16. 7-1 jmu-Java-06异常-01-常见异常 (5 分)
  17. 端口扫描工具终极用法
  18. CAD处理控件Aspose.CAD功能演示:在 C#中以编程方式搜索 DWG 图形文件中的文本
  19. 操作系统(五)I/O设备
  20. 基于永磁同步电机的容积卡尔曼滤波ckf转速位置估计,估计效果很好

热门文章

  1. 浅谈木马的ASP收信方式
  2. 一个程序员老总的年终总结2010版
  3. Java工程师找工作都有什么要求?
  4. 利用单片机控制74HC595显示图案
  5. 华为鸿蒙系统推广,未雨绸缪!为更好推广鸿蒙自研系统,华为已提前做了三大准备!...
  6. TypeScript学习笔记
  7. Apache Spark 3.0 SQL DataFrame和DataSet指南
  8. apt-get update 出错 Could not connect to archive.ubuntukylin.com:10006 (120.240.95.35), connection tim
  9. 步进电机中的力矩(g.cm),转矩(n.m),扭矩(kg.m)有什么区别?
  10. 前端Vue和计网面试题总结