首页 > 系统相关 >内存屏障

内存屏障

时间:2024-03-29 14:25:00浏览次数:32  
标签:__ lfence 屏障 sfence 指令 内存

编译器屏障 Compiler barrier

/* The "volatile" is due to gcc bugs */
#define barrier() __asm__ __volatile__("": : :"memory") 
阻止编译器重排,保证编译程序时在优化屏障之前的指令不会在优化屏障之后执行。

 CPU屏障 CPU barrier
CPU级别内存屏障其作用有两个:
防止指令之间的重排序
保证数据的可见性
指令重排中Load和Store两种操作会有Load-Store、Store-Load、Load-Load、Store-Store这四种可能的乱序结果。

Intel为此提供三种内存屏障指令:

sfence ,实现Store Barrior 会将store buffer中缓存的修改刷入L1 cache中,使得其他cpu核可以观察到这些修改,而且之后的写操作不会被调度到之前,即sfence之前的写操作一定在sfence完成且全局可见;
lfence ,实现Load Barrior 会将invalidate queue失效,强制读取入L1 cache中,而且lfence之后的读操作不会被调度到之前,即lfence之前的读操作一定在lfence完成(并未规定全局可见性);
mfence ,实现Full Barrior 同时刷新store buffer和invalidate queue,保证了mfence前后的读写操作的顺序,同时要求mfence之后写操作结果全局可见之前,mfence之前写操作结果全局可见;
lock 用来修饰当前指令操作的内存只能由当前CPU使用,若指令不操作内存仍然由用,因为这个修饰会让指令操作本身原子化,而且自带Full Barrior效果;还有指令比如IO操作的指令、exch等原子交换的指令,任何带有lock前缀的指令以及CPUID等指令都有内存屏障的作用。
X86-64下仅支持一种指令重排:Store-Load ,即读操作可能会重排到写操作前面,同时不同线程的写操作并没有保证全局可见,例子见《Intel® 64 and IA-32 Architectures Software Developer’s Manual》手册8.6.1、8.2.3.7节。要注意的是这个问题只能用mfence解决,不能靠组合sfence和lfence解决。(用sfence+lfence组合仅可以解决重排问题,但不能解决全局可见性问题,简单理解不如视为sfence和lfence本身也能乱序重拍)

X86-64一般情况根本不会需要使用lfence与sfence这两个指令,除非操作Write-Through内存或使用 non-temporal 指令(NT指令,属于SSE指令集),比如movntdq, movnti, maskmovq,这些指令也使用Write-Through内存策略,通常使用在图形学或视频处理,Linux编程里就需要使用GNC提供的专门的函数(例子见参考资料13:Memory part 5: What programmers can do)。

下面是GNU中的三种内存屏障定义方法,结合了编译器屏障和三种CPU屏障指令

#define lfence() __asm__ __volatile__("lfence": : :"memory") 
#define sfence() __asm__ __volatile__("sfence": : :"memory") 
#define mfence() __asm__ __volatile__("mfence": : :"memory") 
代码中仍然使用lfence()与sfence()这两个内存屏障应该也是一种长远的考虑。按照Interface写代码是最保险的,万一Intel以后出一个采用弱一致模型的CPU,遗留代码出问题就不好了。目前在X86下面视为编译器屏障即可。

GCC 4以后的版本也提供了Built-in的屏障函数__sync_synchronize(),这个屏障函数既是编译屏障又是内存屏障,代码插入这个函数的地方会被安插一条mfence指令。

GCC 内置__sync_synchronize函数:屏障(内置同步)将简单地转换为硬件屏障,如果您使用的是 x86,则可能是栅栏(mfence/sfence)操作,或者其他架构中的等效物。CPU 也可能在运行时做各种优化,最重要的是实际上是乱序执行操作——这条指令告诉它确保加载或存储不能通过这一点,必须在正确的一侧观察同步点。

C++11为内存屏障提供了专门的函数std::atomic_thread_fence,方便移植统一行为而且可以配合内存模型进行设置,比如实现Acquire-release语义:

#include <atomic>
std::atomic_thread_fence(std::memory_order_acquire);
std::atomic_thread_fence(std::memory_order_release);

摘自:https://zhuanlan.zhihu.com/p/43526907,有删改。

参考:

  1. C/C++ Volatile关键词深度剖析
  2. java的并发关键字volatile
  3. 指令重排序
  4. 多处理器编程:从缓存一致性到内存模型
  5. 聊聊原子变量、锁、内存屏障那点事
  6. Why Memory Barriers?中文翻译(上)
  7. LINUX内核内存屏障
  8. Memory Model: 从多处理器到高级语言
  9. 高并发编程--多处理器编程中的一致性问题(上)
  10. 高并发编程--多处理器编程中的一致性问题(下)
  11. 如何理解C++11中的六种内存模型
  12. C/C++11 mappings to processors
  13. When should I use _mm_sfence _mm_lfence and _mm_mfence
  14. Why is (or isn't?) SFENCE + LFENCE equivalent to MFENCE?
  15. Memory part 5: What programmers can do
  16. Memory Reordering Caught in the Act
  17. C++ and the Perils of Double-Checked Locking
  18. 内存模型
  19. UNIX多线程环境下屏障功能(barrier)浅析

标签:__,lfence,屏障,sfence,指令,内存
From: https://www.cnblogs.com/tryst/p/18103754

相关文章

  • 在C语言中,可以通过指针来修改它所指向的内存位置的内容
    在C语言中,可以通过指针来修改它所指向的内存位置的内容。下面是一个例子:#include<stdio.h>intmain(){inta=10;//定义一个变量a,并初始化为10int*p=&a;//定义一个指针p,让它指向a的地址*p=20;//通过指针p修改它所指向的内存位置(即变量......
  • jvm内存模型
    1栈局部变量表存放局部变量局部变量表中的对象是指向堆中对象的地址操作数栈方法内的数据计算程序计数器程序一行代码运行后存放下一行代码的地址本地方法栈方法用native修饰动态链接符号引用转化为直接引用直接引用为方法区的具体地址方法出口2堆新生代伊甸......
  • cesium内存泄漏问题优化
    在vue开发SPA实际项目中,不止涉及到使用cesium可视化的大屏一个界面,在切换页面或者关闭该功能、弹框后,cesium加载的模型,图层,实体等等信息会缓存到电脑的显存中,但是切回cesium界面的时候,又会重新进入页面的挂载周期,进行新的cesium实例的渲染,显存占用会越来越大,达到临界值后,页面会......
  • 动态内存管理
    目录1.为什么要有动态内存分配2.malloc和free2.1malloc2.2free3.calloc和realloc 3.1calloc3.2realloc 4.常⻅的动态内存的错误4.1对NULL指针的解引⽤操作4.2对动态开辟空间的越界访问4.3对⾮动态开辟内存使⽤free释放4.4使⽤free释放⼀块动态开辟......
  • JVM(六)——内存模型与高效并发
    内存模型与高效并发一、java内存模型【java内存模型】是JavaMemoryModel(JMM)简单的说,JMM定义了一套在多线程读写共享数据时(成员变量、数组)时,对数据的可见性、有序性、和原子性的规则和保障1)原子性原子性在学习线程时讲过,下面来个例子简单回顾一下:问题提出,两个线......
  • 原来内存条要开启xmp模式
    明明我购买的是3600mhz的内存条,但是在资源管理器里面显示2600mhz问客服才知道需要开始xmp在bios里面开启重启后一看到主板的页面就按F2或delete我一直按都没有反应查阅资料发现应该是主板设置了快速启动,usb键盘在启动时不通电,那么按就没反应然后我在一见到光的时候就强制关......
  • Java内存马2-Spring内存马
    Spring内存马目录Spring内存马1、Spring&SpringMVC简介2、环境搭建3、Controller内存马4、踩坑日记5、Interceptor内存马1、Spring&SpringMVC简介Spring框架是一个开源的Java应用框架,它提供了一个综合的基础设施,用于构建Java应用程序。Spring框架的主要技术包括:依赖注入(Dep......
  • RowHammer 攻击:内存的隐形威胁
    今天看了一篇IT之家关于AMD处理器受RowHammer内存攻击影响的报道,心血来潮了解了一下RowHammer攻击的原理,把了解到的知识记录下来。RowHammer攻击是一种相对较新的攻击方式,它利用了现代动态随机存取存储器(DRAM)的物理缺陷,这种攻击方式不同于传统的软件漏洞利用,它直接针对......
  • 关于内存函数的介绍
    1.memcpy2.memmove3.memset4.memcmp其中,重点讲解memcpy以及memmove。1.C库函数: void*memcpy(void*str1,constvoid*str2,size_tn) 函数作用:在 str2 复制 n 个字节到 str1。其中,str1用于指向存储复制内容的目标数组     str2指向要复制的......
  • 京东二面:Redis为什么快?我说Redis是纯内存访问的,然后他对我笑了笑。。。。。。
    引言Redis是一个高性能的开源内存数据库,以其快速的读写速度和丰富的数据结构支持而闻名。作为一个轻量级、灵活的键值存储系统,Redis在各种应用场景下都展现出了惊人的性能优势。无论是作为缓存工具、会话管理组件、消息传递媒介,还是在实时数据处理任务和复杂的分布式系统架构中,Re......