内存屏障(__asm__ __volatile__("": : :"memory"))

《C语言编程》__asm__ volatile 内联汇编 __asm__ volatile 内联汇编 阅读详情
内存屏障(memory barrier)
#define set_mb(var, value) do { var = value; mb(); } while (0)
#define mb() __asm__ __volatile__ ("" : : : "memory")

1)set_mb(),mb(),barrier()函数追踪到底,就是__asm__ __volatile__("":::"memory"),而这行代码就是内存屏障。
2)__asm__用于指示编译器在此插入汇编语句
3)__volatile__用于告诉编译器,严禁将此处的汇编语句与其它的语句重组合优化。即:原原本本按原来的样子处理这这里的汇编。
4) memory强制gcc编译器假设RAM所有内存单元均被汇编指令修改,这样cpu中的registers和cache中已缓存的内存单元中的数据将作 废。cpu将不得不在需要的时候重新读取内存中的数据。这就阻止了cpu又将registers,cache中的数据用于去优化指令,而避免去访问内存。
5)"":::表示这是个空指令。barrier()不用在此插入一条串行化汇编指令。在后文将讨论什么叫串行化指令。
6)__asm__,__volatile__,memory在前面已经解释
在linux/include/asm-i386/system.h定义:
#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
7)lock前缀表示将后面这句汇编语句:"addl $0,0(%%esp)"作为cpu的一个内存屏障。
8)addl $0,0(%%esp)表示将数值0加到esp寄存器中,而该寄存器指向栈顶的内存单元。加上一个0,esp寄存器的数值依然不变。即这是一条无用的汇编 指令。在此利用这条无价值的汇编指令来配合lock指令,在__asm__,__volatile__,memory的作用下,用作cpu的内存屏障。
9)set_task_state()带有一个memory barrier,set_task_state()肯定是安全的,但 __set_task_state()可能会快些。


关于barrier()宏实际上也是优化屏障:
#define barrier() __asm__ __volatile__("": : :"memory")
CPU越过内存屏障后,将刷新自己对存储器的缓冲状态。这条语句实际上不生成任何代码,但可使gcc在barrier()之后刷新寄存器对变量的分配。    
             例1:
                1        int a = 5, b = 6;
                2        barrier();
                3        a = b;
     
            在line 3,GCC不会用存放b的寄存器给a赋值,而是重新读内存中的b值,赋值给a。
          
          
例2:
它在进程上下文中将一个元素插入一个单向链表:
new->next=i->next;
wmb();
i->next=new;
同时,如果不加锁地遍历这个单向链表。或者在遍历链表时已经可以看到new,或者new还不在该链表中。两个内存写
事件的顺序必须按照程序顺序进行。否则可能new的next指针将指向一个无效地址,就很可能出现 OOPS!

不论是gcc编译器的优化还是处理器本身采用的大量优化,如Write buffer, Lock-up free, Non- blocking reading, Register allocation, Dynamic scheduling, Multiple issues 等,都可能使得实际执行可能违反程序顺序,因此,引入内存屏障来保证事件的执行次序严格按程序顺序来执行。

使用内存屏障强加的严格的CPU内存事件次序,保证程序的执行看上去象是遵循顺序一致性模型。在当前的实现 中,wmb() 实际上是一个空操作,这是因为目前Intel的CPU系列都遵循“处理机一致性”,所有的写操作是遵循程序顺序的,不会越过前面的读写操作。但是,由于 Intel CPU系列可能会在将来采用更弱的内存一致性模型并且其他体系结构可能采用其他放松的一致性模型,仍然在内核里必须适当地插入wmb()保证内存事件的正 确次序。



在linux/include/asm-i386/alternative.h定义如下:
#define alternative(oldinstr, newinstr, feature) \
asm volatile ("661:\n\t" oldinstr "\n662:\n" \
".section .altinstructions,\"a\"\n" \
" .align 4\n" \
" .long 661b\n" /* label */ \
" .long 663f\n" /* new instruction */ \
" .byte %c0\n" /* feature bit */ \
" .byte 662b-661b\n" /* sourcelen */ \
" .byte 664f-663f\n" /* replacementlen */ \
".previous\n" \
".section .altinstr_replacement,\"ax\"\n" \
"663:\n\t" newinstr "\n664:\n" /* replacement */ \
".previous" :: "i" (feature) : "memory")


1.alternative()宏用于在不同的cpu上优化指令。oldinstr为旧指令,newinstr为新指令,feature为cpu特征位。
2.oldinstr的长度必须>=newinstr的长度。不够将填充空操作符。

注:这是源代码注释,具体我也看不懂

在linux/include/asm-i386/system.h定义如下:
#define mb() alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2)
#define rmb() alternative("lock; addl $0,0(%%esp)", "lfence", X86_FEATURE_XMM2)

#define read_barrier_depends() do { } while(0)

#ifdef CONFIG_X86_OOSTORE
/* Actually there are no OOO store capable CPUs for now that do SSE,but make it already an possibility. */
-->OOO:Out of Order,乱序执行。
-->SSE:SSE是英特尔提出的即MMX之后新一代(当然是几年前了)CPU指令集,最早应用在PIII系列CPU上。
本小段内核注释意即:乱序存储的cpu还没有问世,故CONFIG_X86_OOSTORE也就仍未定义的,wmb()当为后面空宏(在__volatile__作用下,阻止编译器重排顺序优化)。

#define wmb() alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM)
#else
#define wmb() __asm__ __volatile__ ("": : :"memory")
#endif

1.lock前缀表示将后面这句汇编语句:"addl $0,0(%%esp)"作为cpu的一个内存屏障。addl $0,0(%%esp)表示将数值0加到esp寄存器中,而该寄存器指向栈顶的内存单元。加上一个0,esp寄存器的数值依然不变。即这是一条无用的汇编 指令。在此利用这条无价值的汇编指令来配合lock指令,用作cpu的内存屏障。

2.mfence保证系统在后面的memory访问之前,先前的memory访问都已经结束。这是mfence是X86cpu家族中的新指令。

3.新旧指令对比:
以前的源代码:
#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
__asm__用于指示编译器在此插入汇编语句
__volatile__用于告诉编译器,严禁将此处的汇编语句与其它的语句重组合优化。即:原原本本按原来的样子处理这这里的汇编。

现在的源代码:
#define mb() alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2)
两者比较:
比起以前的源代码来少了__asm__和__volatile__。增加了alternative()宏和mfence指令。


而SFENCE指令(在Pentium III中引入)和LFENCE,MFENCE指令(在Pentium 4和Intel Xeon处理器中引入)提供了某些特殊类型内存操作的排序和串行化功能。sfence,lfence,mfence指令是在后继的cpu中新出现的的指 令。

SFENCE,LFENCE,MFENCE指令提供了高效的方式来保证读写内存的排序,这种操作发生在产生弱排序数据的程序和读取这个数据的程序之间。
SFENCE——串行化发生在SFENCE指令之前的写操作但是不影响读操作。
LFENCE——串行化发生在SFENCE指令之前的读操作但是不影响写操作。
MFENCE——串行化发生在MFENCE指令之前的读写操作。
注意:SFENCE,LFENCE,MFENCE指令提供了比CPUID指令更灵活有效的控制内存排序的方式。

sfence:在sfence指令前的写操作当必须在sfence指令后的写操作前完成。
lfence:在lfence指令前的读操作当必须在lfence指令后的读操作前完成。
mfence:在mfence指令前的读写操作当必须在mfence指令后的读写操作前完成。

其实这里是用mfence新指令来替换老的指令串:__asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")。
mfence的执行效果就等效于 __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")的执行效果。只不过,__asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")是在以前的cpu平台上所设计的,借助于编译器__asm__,__volatile__,lock这些指令来实现内存屏障。而在 Pentium 4和Intel Xeon 处理器中由于已经引入了mfence指令,无须再用这一套指令,直接调用这一条指令即ok。而alternative()宏就是用于这个优化指令的替换, 用新的指令来替换老的指令串。


这些函数在已编译的指令流中插入硬件内存屏障;具体的插入方法是平台相关的。rmb(读内存屏障)保证了屏障之前的读操作一定会在后来的读操作执行之前完成。wmb 保证写操作不会乱序,mb 指令保证了两者都不会。这些函数都是 barrier函数的超集。
内存屏障出现因为编译器或现在的处理器常会自作聪明地对指令序列进行一些处理,比如数据缓存,读写指令乱序执 行等等。如果优化对象是普通内存,那么一般会提升性能而且不会产生逻辑错误。但如果对 I/O操作进行类似优化很可能造成致命错误。所以要使用内存屏障,以强制该语句前后的指令以正确的次序完成。其实在指令序列中放一个wmb的效果是使得指 令执行到该处时,把所有缓存的数据写到该写的地方,同时使得wmb前面的写指令一定会在wmb的写指令之前执行
linux内核中的内存屏障 前言        之前读了关于顺序一致性和缓存一致性讨论的文章,感觉豁然开朗。对linux内核中出现的种种同步和屏障,想做一点总结。 缓存一致性        之前一直认为linux中很多东西是用来保证缓存一致性的,其实不是。缓存一致性绝大部分是靠硬件机制实现的, 阅读详情

相关推荐

LLVM 中 asm volatile(““ ::: “memory“)

是一个强大的底层工具,用于在多线程编程和系统编程中强制内存访问的可见性和顺序。它是“编译器的护栏”,确保生成的汇编代码符合我们的逻辑预期。当你需要防止编译器优化掉内存访问,或者强制内存访问顺序,但又不想影响 CPU 执行效率时,使用它。在 x86/64 等强内存序架构上,它通常足以保证多线程的正确性,因为 x86 的硬件内存模型本身就相对较强(StoreLoad 重排除外)。在弱内存序架构上,它必须与 CPU 内存屏障指令结合使用才能万无一失。

u010523811的博客 935

__asm__ __volatile__内嵌汇编用法简述

 __asm__ __volatile__内嵌汇编用法简述 在阅读C/C++原码时经常会遇到内联汇编的情况,下面简要介绍下__asm__ __volatile__内嵌汇编用法。因为我们华清远见教学平台是ARM体系结构的,所以下面的示例都是用ARM汇编。 带有C/C++表达式的内联汇编格式为: __asm__ __volatile__("Instruction List" : Outpu

lemon_fantasy的专栏 3810

【G4基础08】GPS-2-Macro Commands宏命令

GPS-2

adelall的博客 3738

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

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

sxudong2010的博客 3093

mongoDB 数据莫名其妙的没了

问题 之前没有接触过mongoDB,然后接手一个项目使用的是MongoDB,我就跟着网上的教程搭建一个MongoDB的服务,并运行起来。 一开始没有啥问题,成功的把服务与MongoDB都启动以来,运行也没有问题。但是过了几天,我再次打开时发现,以前的数据神奇的消失了。我还在想,是有什么定时清除的么,还是什么原因导致崩了然后数据就被清理了。 查找原因 第一次遇到我没有在意,重启了一下MongoDB,...

技术熊的博客小窝 1万+

YOLOv5轻量化实战:从Ghost模块到工业级部署的完整指南

本文详细介绍了YOLOv5轻量化实战,重点解析了Ghost模块在工业检测中的应用及其优化策略。通过Ghost卷积技术,模型参数量和GFLOPs显著降低,同时保持高精度,适用于实时性要求严格的工业场景。文章还提供了从模型优化到TensorRT加速的完整部署指南,助力开发者实现高效工业级应用。

weixin_28223453的博客 487

__asm__ __volatile__("": : :"memory")

__asm__ __volatile__("": : :"memory");内存屏障(memory barrier)  #define set_mb(var, value) do { var = value; mb(); } while (0)  #define mb() __asm__ __volatile__ ("" : : : "memory")  1)set_mb(),mb(),

穆先生的专栏 3255

五段式S型算法笔记

又因为有 v-v0= 0.5jt通式: 所以有 vm-v0= 0.5jtm 所以有4vm-4v0= 2jtm。算法1: v=2vm-v0-0.5*jt+2jt*tm-2jtm*tm。加加速度j 自己设置 已知,vmax自己设置已知;所以有4vm-4v0= 2jtm带入算法1。

qq_36658033的博客 680

__asm__ __volatile__("": : :"memory")含义

__asm__ __volatile__("": : :"memory")含义   首先看看__set_current_state()和set_current_state()函数的区别 #define __set_current_state(state_value) \ do { current->state = (state_value); } while (0)

Wait for 的专栏 8894

2024年全国大学生信息安全竞赛安徽省赛网络系统建设与运维赛项-网络构建真题

该网络工程方案主要包含基础配置、有线网络、无线网络、出口网络、运维配置和SDN网络六个部分。基础配置包括设备接口设置、SSH服务开启和SNMP功能配置。有线网络部分重点部署VLAN、MSTP、VRRP和OSPF协议,实现网络冗余和负载均衡。无线网络规划了AP点位、信号覆盖和用户接入策略,包括SSID配置、频段优化和安全认证。出口网络配置了NAT转换、VPN隧道和流量审计功能。运维方面搭建了监控平台实时监测设备状态。SDN网络部分通过控制器实现流量管控。整个方案实现了多业务隔离、高可用性网络架构和

weixin_42221934的博客 1174

【Android 11】使用Android Studio调试系统应用之Settings移植(三):构建Settings、SettingsLib项目文件

基于android 11,本系列文章力争实用,讲解使用AS调试系统app的方法,并提供了配套源下载,供学习调试。上一篇文章[Android 11]使用Android Studio调试系统应用(二):依赖分析、android.bp、静态和动态依赖,讲解了如何搭建编译服务器,如何下载AOSP源码,如何切换到AOSP的指定分支(android-11-r39),以及如何编译、解决编译错误、运行模拟器,本文将开始讲解如何构建Settings的AS工程文件! 走过、路过,有用过的同学,记得给个赞O(∩_∩)O哈!

上周的博客 2677

linux-6.2.1源码阅读1——内存屏障 asm volatile(““ : : : “memory“);

linux-6.2.1,mb(),barrier()函数讲解

蒲公英殇的博客 1777

【第三方互联】12、支付宝(Alipay)授权第三方登录

我们创建了支付宝开放平台的网页&移动应用,审核通过后,我们需要拿到appid,支付宝公钥,私钥进项开发 一、添加应用信息至项目环境中 我们保存了 appid、应用私钥、支付宝公钥、支付宝回调地址等信息,这里的公钥为支付宝开放平台为我们生成的“支付宝公钥” 二、引入 Maven 依赖 <!-- 支付宝SDK --> <dependency> <g.........

JACKAL 21万+

内存屏障--- asm volatile("" ::: "memory")

Compiler memory barrier These barriers prevent a compiler from reordering instructions, they do not prevent reordering by CPU. The GNU inline assembler statement asm volatile("" ::: "memory");

     KISSMonX 2万+

软考「系统规划与管理师(第2版)」抱佛脚|案例分析预测

规划类(系统/数据/云)+ 服务过程找错改进 + 风险应急终止三大块各备一套成熟模板,术语统一按第2版新教材口径,案例分析 45 分线的希望就大很多。

软件行业技术文化交流。 71

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

gcc内嵌汇编简单介绍,以及 __asm__ volatile ("": : :"memory")中memory解释

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

szhlcy的博客 5163

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

uboot中语句__asm__ __volatile__("": : :"memory");理解

The GCC manual says using "asm volatile" prevents the asm instruction from being "moved  significantly" and adding "memory" to the clobber list prevents GCC from keeping memory values cached  in

tianshangyu333的专栏 849

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

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

__asm__ __volatile__ (“” : : : “memory”) 该语句创建一个编译器层的存储屏障(memory barrier),告诉编译器不要越过该屏障优化存储器的访问顺序.举例来说,如果你要访问某地址需要特殊的顺序(可能因为那地址的数据是其它设备的返回值)就要告诉编译器不要优化你的访问顺序,防止编译器会考虑效率问题而优化你的读写顺序. 在这个例子中先让某地址的值加1,然后读...

qq_36412526的博客 4222

volatile 与内存屏障

volatile   c语言中 volatile 关键字用于告诉编译器,严禁将此处的汇编语句与其它的语句重组合优化。volatile只能保证编译器不会做乱序执行优化.         1. 不对*p操作生成乱序指令(通常如此,具体请看后面的解释) (比如条件判断)         2. 每次从*p取数据的时候,一定会进行一次访存操作,哪怕前面不久才取过*p的值放在寄存器里。 比如对

dzhj11的专栏 2929

内存屏障(memory barrier)

内存屏障(memory barrier) #define set_mb(var, value) do { var = value; mb(); } while (0) #define mb() __asm__ __volatile__ ("" : : : "memory") 1)set_mb(),mb(),barrier()函数追踪到底,就是__asm__ __volatile__("":::"m

云,无处不在 雾,是下一代 975

__asm__ __volatile__("": : :"memory")等系列问题

__asm__ __volatile__("": ::"memory") 内存屏障(memory barrier)   #define set_mb(var, value) do { var = value;mb(); } while (0)   #define mb() __asm__ __volatile__ ("" : : :"memory") 1)set_mb(),mb(),b

君子当自强不息 5278

volatile与内存屏障总结

一. 内存屏障 Memory Barrior 1.1 重排序 同步的目的是保证不同执行流对共享数据并发操作的一致性。在单核时代,使用原子变量就很容易达成这一目的。甚至因为CPU的一些访存特性,对某些内存对齐数据的读或写也具有原子的特性。但在多核架构下即使操作是原子的,仍然会因为其他原因导致同步失效。 首先是现代编译器的代码优化和编译器指令重排可能会影响到代码的执行顺序。 其次还有指令执行级...

Poo_Chai的博客 3329

__asm__ __volatile__ ("" : : : "memory")

1.内存屏障(memory barrier)   #define set_mb(var, value) do { var = value; mb(); } while (0)   #define mb() __asm__ __volatile__ ("" : : : "memory") 1)set_mb(),mb(),barrier()函数追踪到底,就是__asm__ __volatile__("

xiaofeng_yan的专栏 1341
上一篇: linux下控制CPU不降频命令
下一篇: Linux 对SSD硬盘优化的方法
whycold
博客等级 码龄19年 280粉丝 44原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值