你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

什么时候需要使用volatile关键字吗?

[复制链接]
gaosmile 发布时间:2020-7-26 22:05
想必大家平时都见过volatile关键字,可是大家知道什么时候需要使用volatile关键字吗?
/ [- f4 w. c1 [' i5 @4 y5 J' e. [5 T
直接看下面代码:

  1. 7 T  _! x& s7 Y, C" T8 M
  2. int a = 100;: W0 n4 d4 Y2 I; F' S  [

  3. 0 M; h( _) R- j) R) U" S" V
  4. while (a == 100) {
    1 j3 ^7 Y) q7 \- L. T& {9 D: T& L
  5. // code
    ( y/ p( u. ~- Q6 ]: v; o' O
  6. }
复制代码
9 ]9 u" J! D% y, D9 F' ]9 D
这段程序编译时,如果编译器发现程序始终没有企图改变a的值,那它可能就会优化这段代码,变成while(true)的死循环使得程序执行的更快,然而这种优化有时候会变成过度优化,编译器有时候可能没有意识到程序会改变a的值,却做了这种优化导致程序没有产生预期的行为。
这里为了产生预期的行为,需要阻止编译器做这种优化,可以使用volatile关键字修饰。
  1. * @4 o2 W/ ~# e/ i, ?
  2. volatile int a = 100;
复制代码
$ J/ E+ ]# P' i3 U1 H
volatile关键字和const关键字相对应,const关键字告诉编译器其修饰的变量是只读的,编译器根据只读属性做一些操作,而volatile关键字告诉编译器其修饰的变量是易变的,同理编译器根据易变属性也会做一些操作。它会确保修饰的变量每次都读操作都从内存里读取,每次写操作都将值写到内存里。volatile关键字就是给编译器做个提示,告诉编译器不要对修饰的变量做过度的优化,提示编译器该变量的值可能会以其它形式被改变。
volatile修饰结构体时,结构体的成员也是volatile的吗

  1. 1 P8 c$ O8 ?2 F. b
  2. struct A {( Z8 m+ _; Y1 B0 O4 k+ ~/ t
  3.     int data;
    ( g& u( S3 y% Q5 U8 n9 m5 {( q" Q
  4. };
    ) k+ d1 r8 e5 d
  5. volatile A a;
    ' D5 o6 \6 `4 G8 T6 f* |6 ^
  6. const A b;
复制代码
7 g' h9 Y3 `; m1 T0 [) ]
答案是结构体内所有的都是volatile,引用c++标准里的一句话:
  1. : n) h2 e5 H1 O* r
  2. [Note: volatile is a hint to the implementation to avoid aggressive optimization involving the object
    6 \2 `, f: X  i3 n
  3. because the value of the object might be changed by means undetectable by an implementation. $ s- ~  F7 W8 |$ K* r/ \# x) v
  4. See 1.9 for detailed semantics. In general, the semantics of volatile are intended to be the same ! ~) C3 a  \; M: L0 H
  5. in C + + as they are in C. ]
复制代码

* H, j" k, `/ D% I
这里大体可以理解为一个对象是volatile,那对象里所有的成员也都是volatile。其实const和volatile可以理解为是硬币的两面,我们经常听到看到传说中的CV修饰词就是const和volatile关键字。
volatile可以保证原子性吗
想必大家都知道答案,volatile只保证内存可见性,不能保证操作是原子的,拿i++举例:

  1. 6 W5 W9 s7 x6 u  G2 i0 ~
  2. volatile int i = 0;0 G) b7 X3 B6 {* V
  3. i++; // i = i + 1
复制代码

8 Q! A8 x' w1 j
i++ 相当于i=i+1,而i=i+1其实可以分解为好几步:
  • 先读取i的值到tmp
  • 增加tmp的值
  • 把tmp的值写回到i的地址里
    3 O1 J: V* [% e4 v$ B
而volatile只能保证内存可见,可以理解为上述三步中的每一步都是原子的,但是三步合起来却不一定是原子的,因为在多线程中三步中间可能插入一些其它操作改变了预期的行为,所以volatile不能用在多线程中,多线程中的原子操作还是需要使用atomic。单例模式的double check方法中instance变量为什么需要使用volatile修饰也是这个原理。
小总结
8 y* Z9 @* G8 r" R$ [1 ~# Z" L
tips:volatile不能解决多线程安全问题,针对特种内存才需要使用volatile,它和atomic的特点如下:• std::atomic用于多线程访问的数据,且不用互斥量,用于并发编程中• volatile用于读写操作不可以被优化掉的内存,用于特种内存中
( _- ~9 a. B9 h0 y/ a1 @
赞 收藏 评论1 发布时间:2020-7-26 22:05

举报

1个回答
李康1202 回答时间:2020-7-27 08:48:57
顶一下
mark.png
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版