0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C语言中的关键字volatile到底有什么用呢

冬至配饺子 来源:码农的荒岛求生 作者:陆小风 2022-08-19 15:20 次阅读

C语言时有一个奇怪的关键字volatile,这到底有什么用呢?

volatile与编译器

首先来看这样一段代码:

poYBAGL_OPqAJcX1AAAmuspJiPM513.png

编译一下,注意,这里使用O2优化

poYBAGL_OQuAUL6RAABH_m-ekkU022.png

让我们仔细看看生成的这段汇编

poYBAGL_ORuAbQaYAAAx5NlEoUA148.png

其中L2这一段即为while循环,这段指令是经过编译器优化的,可以看到,决定能否跳出循环是通过检查寄存器eax来完成的,而没有检查变量busy所在内存的真实内容。注意,对于这段代码来说这里的优化是正确的,但问题是如果还有其它代码修改了变量busy,那么这里的优化会导致其它代码对变量busy的修改根本就不能生效,就像这样:

poYBAGL_OS2AX76OAABCqHuCaHk299.png

如果wait函数中while循环对应的机器指令仅仅从寄存器中读取数据那么即使B线程的signal函数修改了busy变量也不能让wait函数从循环中跳出来。如果你对busy变量使用volatile修饰,生成的指令就变成这样了:

poYBAGL_OUGAJgWUAAB5XeDiP-A019.png

注意看此时L2这一段,每次都从busy变量所在的内存中读取数据并存放在eax,然后再去判断,这样就能确保每次都能读取到busy变量的最新值。实际上你可以把寄存器eax当做busy所在内存的cache,当cache(寄存器)和内存中的数据一致时不会有任何问题,但当cache与内存中的数据不一致时(也就是内存已被更新但cache保存的还是旧数据),程序的运行往往出乎预料。除了多线程的例子,还有一类就是signal handler以及硬件修改该变量(用C语言与硬件交互式时经常遇到),如果编译器生成文章开头那样的指令那么等待线程将检测不到signal handler或者硬件对变量的修改。

pYYBAGL_OVOADcaxAABWCJPCGqM654.png

因此在这里我们需要告诉编译器:“不要耍小聪明,不要只从寄存器中读数据,这个变量可能在其它地方已经被修改了,使用时从内存中获取最新数据”。现在是时候简单总结一下了,volatile仅仅阻止编译器试图去优化
对变量的读取操作


volatile与多线程一定要注意volatile仅仅确保变量的可见性,但和变量的原子访问没有半毛钱关系,这是两个完全不同的任务。假设有一个非常复杂的结构体struct foo:

poYBAGL_OWaACKRUAABuHEE_1Qk178.png

你仅仅用volatile去修饰变量foo只是确保了当该变量被thread1修改后我们能在thread2中读取到最新值,但是这解决不了多线程并发读写需要原子访问foo的问题。确保变量原子性访问一般都采用锁,当使用锁时,锁本身就包含了volatile提供能力,即,确保变量的可见性,因此当使用锁时没有必要使用volatile。

volatile与memory order有的同学可能会想如果我想用volatile修饰的变量没有那么复杂,仅仅是一个int,就像这样:

pYYBAGL_OXeAIeSZAAAVhwVO_pw844.png

A线程读取busy变量,B线程更新busy变量,当A检测到busy变化后执行特定操作,这样可行吗?既然通过volatile修饰后可以确保每次都从内存中读取busy,那么应该可以这样使用吧。然而,计算机在概念上可能相对简单些,但在工程实践中是复杂的。我们知道由于CPU与内存之间的速度差异非常大,CPU与内存之间有一层cache,CPU其实并没有直接读取内存,cache的存在会让问题复杂起来,限于篇幅与本文主题这里不再展开。为优化内存读写,CPU可能会对内存读写操作进行指令重排,reordering,带来的后果就是:假设在线程1中先后执行第N行代码与第N+1行代码,但在线程2看来却是第N+1行代码先生效,假设X的初始值为0,Y的初始值为1:

poYBAGL_OYmASB2jAAAdTvpeW0g039.png

当线程2检测到busy为0后读取X的值,此时读取到的X值可能为0。为解决这一问题,我们需要的不是volatile,volatile解决不了reordering问题,我们需要的是内存屏障,memory barrier。内存屏障是一类机器指令,该指令对处理器在该屏障指令之前与之后的内存操作进行了限制,确保不会出现重排问题。而内存屏障带来的效果依然能够涵盖volatile提供的功能,因此也不需要volatile。可以看到,在多线程环境下我们几乎总是不会使用volatile关键字。



审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 处理器
    +关注

    关注

    68

    文章

    18288

    浏览量

    222176
  • 寄存器
    +关注

    关注

    30

    文章

    5032

    浏览量

    117746
  • C语言
    +关注

    关注

    180

    文章

    7533

    浏览量

    128788
收藏 人收藏

    评论

    相关推荐

    c语言中 volatile _Bool 关键字说明

    volatile 关键字?volatile总是与优化有关,编译器一种技术叫做数据流分析,分析程序中的变量在哪里赋值、在哪里使用、在哪里
    发表于 01-06 10:46

    请问关键字volatile该什么时候

    这东西的概念我懂,但是实际编程时,关键字volatile该什么时候啊,求大神来点经验之谈!
    发表于 04-28 09:06

    编译器的“关键字到底有关键

    DSP编程什么技巧?使用代码优化时必须考虑哪些问题?C28x的编译器支持哪些“关键字”?编译器的“关键字到底有
    发表于 04-19 06:32

    【原创分享】单片机编程关键字volatile

    很多人来说,根本没见过这个关键字,不知道它的存在。也有很多人知道它的存在,根本没用过,我对它有种“杨家有女初长成,养在深闺无人识”的感觉。那么volatile关键字到底是什么意思
    发表于 06-29 11:17

    C语言的标识符和关键字哪些

    五、C语言的标识符和关键字一个完整的1.C语言的标识符所谓标识符,实际上是一些由程序编写者自定义的名称,类似于PIC单片机汇编
    发表于 07-15 09:31

    c语言volatile关键字在单片机中有什么作用

    c语言volatile关键字在单片机中的作用volatile 的意思是“易失的,易改变的”。这个限定词的含义是向编译器指明变量的内容可能会由
    发表于 07-15 07:36

    C语言volatile关键字详解 精选资料分享

    1.volatile和什么有关百度翻译是这样子翻译volatile的:图1-1 百度翻译volatile截图volatile属于C
    发表于 07-22 07:20

    volatile关键字应用场景及示例

    volatile关键字1.应用场景2.示例1.应用场景volatile关键字分析,往往应用在三种场合1)多线程编程共享全局变量的时候,该全局变量要加上
    发表于 08-24 07:21

    Volatile关键字对于嵌入式开发有什么作用

    前言在进行嵌入式开发中,我们往往会看到一个名为volatile或者__IO的关键字,那么,它们对于嵌入式开发有什么作用?浅析volatile数据类型实际上,__IO和
    发表于 11-05 09:20

    C语言volatile关键字之间什么关系?

    C语言volatile关键字之间什么关系?
    发表于 11-11 07:01

    嵌入式程序员常见的const、static、volatile关键字

    嵌入式程序员const、static、volatile三个关键字的朴素认识摘要:在C语言程序编写中,const、static关键字是比较熟悉
    发表于 12-21 06:08

    C语言中关键字static的作用是什么

    C语言中关键字static的作用是什么?预处理指令#define 声明一个函数,输入天数得到多少秒?
    发表于 12-24 06:53

    C语言中volatile关键字

    volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改。
    发表于 05-27 09:32 3181次阅读

    【嵌入式】C语言中volatile关键字

    volatile06. 附录01. volatile概述volatile是C语言中的一个关键字。将变量定义为
    发表于 10-21 10:21 6次下载
    【嵌入式】C<b class='flag-5'>语言中</b><b class='flag-5'>volatile</b><b class='flag-5'>关键字</b>

    C语言中volatile是什么

    学C语言时有一个奇怪的关键字volatile,这到底有什么用呢?
    的头像 发表于 02-17 14:29 987次阅读
    C<b class='flag-5'>语言中</b>的<b class='flag-5'>volatile</b>是什么