编译器优化 → C关键字volatile → memory破坏描述符zz

LLVM 中 asm volatile(““ ::: “memory“) 是一个强大的底层工具,用于在多线程编程和系统编程中强制内存访问的可见性和顺序。它是“编译器的护栏”,确保生成的汇编代码符合我们的逻辑预期。当你需要防止编译器优化掉内存访问,或者强制内存访问顺序,但又不想影响 CPU 执行效率时,使用它。在 x86/64 等强内存序架构上,它通常足以保证多线程的正确性,因为 x86 的硬件内存模型本身就相对较强(StoreLoad 重排除外)。在弱内存序架构上,它必须与 CPU 内存屏障指令结合使用才能万无一失。 阅读详情
 “memory”比较特殊,可能是内嵌汇编中最难懂部分。为解释清楚它,先介绍一下编译器的优化知识,再看C关键字volatile。最后去看该描述符。

1、编译器优化介绍
   内存访问速度远不及CPU处理速度,为提高机器整体性能,在硬件上引入硬件高速缓存Cache,加速对内存的访问。另外在现代CPU中指令的执行并不一定严格按照顺序执行,没有相关性的指令可以乱序执行,以充分利用CPU的指令流水线,提高执行速度。以上是硬件级别的优化。再看软件一级的优化:一种是在编写代码时由程序员优化,另一种是由编译器进行优化。编译器优化常用的方法有:将内存变量缓存到寄存器;调整指令顺序充分利用CPU指令流水线,常见的是重新排序读写指令。对常规内存进行优化的时候,这些优化是透明的,而且效率很好。由编译器优化或者硬件重新排序引起的问题的解决办法是在从硬件(或者其他处理器)的角度看必须以特定顺序执行的操作之间设置内存屏障(memory barrier),linux 提供了一个宏解决编译器的执行顺序问题。
                            void Barrier(void)
这个函数通知编译器插入一个内存屏障,但对硬件无效,编译后的代码会把当前CPU寄存器中的所有修改过的数值存入内存,需要这些数据的时候再重新从内存中读出。

2、C语言关键字volatile
    C语言关键字volatile(注意它是用来修饰变量而不是上面介绍的__volatile__)表明某个变量的值可能在外部被改变,因此对这些变量的存取不能缓存到寄存器,每次使用时需要重新存取。该关键字在多线程环境下经常使用,因为在编写多线程的程序时,同一个变量可能被多个线程修改,而程序通过该变量同步各个线程,例如:
    DWORD __stdcall threadFunc(LPVOID signal)
    {
       int* intSignal=reinterpret_cast<int*>(signal);
       *intSignal=2;
       while(*intSignal!=1)
                 sleep(1000);
       return 0;
    }
该线程启动时将intSignal 置为2,然后循环等待直到intSignal 为1 时退出。显然intSignal的值必须在外部被改变,否则该线程不会退出。但是实际运行的时候该线程却不会退出,即使在外部将它的值改为1,看一下对应的伪汇编代码就明白了:
   mov ax,signal
    label:
    if(ax!=1)
              goto label

   对于C编译器来说,它并不知道这个值会被其他线程修改。自然就把它cache在寄存器里面。记住,C 编译器是没有线程概念的!这时候就需要用到volatile。volatile 的本意是指:这个值可能会在当前线程外部被改变。也就是说,我们要在threadFunc中的intSignal前面加上volatile关键字,这时候,编译器知道该变量的值会在外部改变,因此每次访问该变量时会重新读取,所作的循环变为如下面伪码所示:
   label:
    mov ax,signal
    if(ax!=1)
             goto label

3、Memory
     有了上面的知识就不难理解Memory修改描述符了,Memory描述符告知GCC:
     1)不要将该段内嵌汇编指令与前面的指令重新排序;也就是在执行内嵌汇编代码之前,它前面的指令都执行完毕
     2)不要将变量缓存到寄存器,因为这段代码可能会用到内存变量,而这些内存变量会以不可预知的方式发生改变,因此GCC插入必要的代码先将缓存到寄存器的变量值写回内存,如果后面又访问这些变量,需要重新访问内存。

   如果汇编指令修改了内存,但是GCC 本身却察觉不到,因为在输出部分没有描述,此时就需要在修改描述部分增加“memory”,告诉GCC 内存已经被修改,GCC 得知这个信息后,就会在这段指令之前,插入必要的指令将前面因为优化Cache 到寄存器中的变量值先写回内存,如果以后又要使用这些变量再重新读取。

   使用“volatile”也可以达到这个目的,但是我们在每个变量前增加该关键字,不如使用“memory”方便。
GCC内联汇编:从编译器视角看指令融合与优化屏障 本文深入解析GCC内联汇编编译器视角下的工作机制,重点探讨指令融合与优化屏障的实现原理。详细分析volatile关键字的作用与限制,内存一致性控制机制,以及如何通过正确的约束和破坏列表避免编译器优化导致的语义错误,为系统级编程提供实践指导。 阅读详情

相关推荐

Linux内存描述符mm_struct实例详解

Linux对于内存的管理涉及到非常多的方面,这篇文章首先从对进程虚拟地址空间的管理说起,具体实例代码大家通过本文学习下吧

编译器编译过程以及对关键字的处理(C语言)

编译器编译过程以及对关键字的处理

weixin_44164532的博客 462

C语言 关于优化

(一)应用级: 1)设计逻辑 2) (二)算法语言: 1)优化下面的for循环 优化前: for(int i=0;i<1000;i++){ for(int j=0;j<100;j++){ for(int k=0;k<10;k++){ function(i,j,k); } } } ...

书山有路勤为径 419

C语言 之编译器优化

C语言的编译器会对变量和代码进行一定的优化,我们看下面这个例子。 int a,b,c; a=1; b=a; c=b; 这个程序正常运行的时候会这样子:先把a指向的内存空间内放入1 再把a指向的内存空间里的数读出来放到b指向的内存空间, 最后再把b指向的内存空间里的数读出来放到c指向的内存空间里。 然而编译器要对这个程序进行一定

Dezeming的博客 1万+

GCC内嵌汇编之语法详解

开发Arm程序的时候,大多数时候使用C/C++语言就可以了,但汇编语言在某些情况下能够实现一些C语言无法实现的功能,这时候就要调用一些汇编语言的程序.我们需要大概了解一下在C语言中如何嵌入汇编语言.内嵌汇编语法如下:        __asm__(汇编语句模板: 输出部分: 输入部分: 破坏描述部分) 共四个部分:汇编语句模板,输出部分,输入部分,破坏描述部分,各部分使用“:”格开,汇编语句模板必...

开挂的熊猫 1万+

C语言全部关键字解析

enum是C语言中的关键字,用于定义枚举类型。枚举类型是一种用户自定义的数据类型,用于定义一组具有相关性的常量值。枚举类型可以帮助提高代码的可读性和可维护性,使程序员能够更清晰地表示一组相关的常量。enum 枚举类型名 {枚举常量1,枚举常量2,...其中,枚举类型名是用户自定义的标识符,用于表示枚举类型。枚举常量是一组有序的常量值,用逗号分隔。枚举常量可以通过枚举类型名和常量名来引用。在程序中,可以使用枚举类型名和枚举常量名来表示枚举常量的值。

qq_53092944的博客 1123

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

一、volatile介绍 volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。下面举例说明。在DSP开发中,经常需要等待某个事件的触发,所以经常会写出这样的程序: 这段...

小白的逆袭 8万+

c++ 无法读取内存_详解C中volatile关键字

volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。下面举例说明。在DSP开发中,经常需要等待某个事件的触发,所以经常会写出这样的程序:short 这段程序...

weixin_39940957的博客 1124

详解C中volatile关键字

volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。下面举例说明。在DSP开发中,经常需要等待某个事件的触发,所以经常会写出这样的程序: short flag; void...

十年代码写十年 351

c语言volatile原理,C++ 中 volatile 的使用

简单地说就是防止编译器对代码进行优化.好比以下程序:XBYTE[2]=0x55;XBYTE[2]=0x56;XBYTE[2]=0x57;XBYTE[2]=0x58;对外部硬件而言,上述四条语句分别表示不一样的操做,会产生四种不一样的动做,可是编译器却会对上述四条语句进行优化,认为只有XBYTE[2]=0x58(即忽略前三条语句,只产生一条机器代码)。若是键入volatile,则编译器会逐一的进行编...

weixin_35705523的博客 1168

C++ volatile关键字深度解析:编译器优化与硬件交互的正确姿势

在计算机系统中,编译器优化是提升程序性能的关键技术,通过消除冗余代码、重排指令顺序等手段生成高效机器码。然而,当程序需要与外部硬件设备交互时,这种优化可能导致严重问题——编译器无法感知硬件寄存器的异步变化。volatile关键字正是为解决这一矛盾而生,它强制编译器每次访问变量时都直接从内存读取或写入,确保硬件交互的正确性。在嵌入式开发、设备驱动等场景中,volatile是连接软件与硬件的桥梁,但需注意它并非线程同步工具,多线程场景应使用atomic类型。本文通过内存映射I/O、信号处理等实例,详解volat

weixin_30512089的博客 357

volatile、restrict、gcc优化、内嵌汇编memory修饰符

GCC在C语言中内嵌汇编-转载 http://hi.baidu.com/liu_bin0101/blog/item/433103007852b216738b658d.html 在内嵌汇编中,可以将C语言表达式指定为汇编指令的操作数,而且不用去管如何将C语言表达式的值读入哪个寄存器,以及如何将计算结果写回C 变量,你只要告诉程序中C语言表达式与汇编指令操作数之间的对应关系即可, GCC会...

1113

C语言——关键字volatile

volatile 关键字和 const 对应,用来修饰变量,通常用于建立语言级别的什么是 memory barrier?也称为内存栅栏,是一种指令或指令序列,用于控制处理器和内存的交互,并确保对内存的访问按照预期的顺序和时序进行。在并发编程中,当多个线程或处理器同时访问共享内存时,由于缓存和指令重排序等优化机制的存在,可能会导致数据不一致或破坏程序的正确执行顺序。内存屏障的作用就是在多线程或多处理器之间建立障碍,以限制或规范内存操作的重排序和可见性。

m0_69844675的博客 212

C语言关键字深度解析:从static、volatile到模块化编程实战

在C语言编程中,数据类型、存储类别和流程控制是构建程序的基础。数据类型关键字如int、char定义了数据的存储格式,而存储类别关键字如static、extern则决定了变量的生命周期与作用域,这是理解程序内存布局的关键。深入掌握这些概念,能显著提升代码的效率和可维护性,尤其在嵌入式系统开发中,对volatile关键字的正确使用,能确保程序与硬件寄存器的可靠交互。本文聚焦于static、const、volatile等核心关键字,通过模块化编程、多线程同步等典型应用场景,剖析其底层原理与实战技巧,帮助开发者避免

weixin_34262482的博客 409

__asm__ __volatile__ (“” : : : “memory”) 内存屏障

在内嵌汇编中,可以将C语言表达式指定为汇编指令的操作数,而且不用去管如何将C语言表达式的值读入哪个寄存器,以及如何将计算结果写回C 变量,你只要告诉程序中C语言表达式与汇编指令操作数之间的对应关系即可, GCC会自动插入代码完成必要的操作。 1、简单的内嵌汇编 例: __asm__ __volatile__("hlt");`` "__asm__"表示后面的代码为内嵌汇编,"asm"是"__asm__"的别名。"__volatile__"表示编译器不要优化代码,后面的指令保留原样,"volatile"是它的别

sxudong2010的博客 3082
上一篇: C和C++中如何互相调用(#ifdef __cplusplus)
下一篇: 编写完成端口网络服务器的一些说明 (1)
sun201201
博客等级 码龄21年 1粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值