内存屏障简略介绍

简介: 内存屏障简略介绍

内存屏障,也称内存栅栏,内存栅障,屏障指令等, 是一类同步屏障指令,是CPU或编译器在对内存随机访问的操作中的一个同步点,使得此点之前的所有读写操作都执行后才可以开始执行此点之后的操作。

大多数现代计算机为了提高性能而采取乱序执行,这使得内存屏障成为必须。

语义上,内存屏障之前的所有写操作都要写入内存;内存屏障之后的读操作都可以获得同步屏障之前的写操作的结果。因此,对于敏感的程序块,写操作之后、读操作之前可以插入内存屏障。

大多数处理器提供了内存屏障指令:

完全内存屏障(full memory barrier)保障了早于屏障的内存读写操作的结果提交到内存之后,再执行晚于屏障的读写操作。

内存读屏障(read memory barrier)仅确保了内存读操作;

内存写屏障(write memory barrier)仅保证了内存写操作。

Windows API的内存屏障实现,下述同步函数使用适当的屏障来确保内存有序:

1、进出临界区(critical section)的函数

2、触发(signaled)同步对象的函数

3、’等待函数(Wait function)

4、互锁函数(Interlocked function) [1]

多线程编程:

多线程程序通常使用高层程序设计语言中的同步原语,如Java与.NET Framework,或者API如pthread或Windows API。因此一般不需要明确使用内存屏障。

内存可见性:

内存可见性问题,主要是高速缓存与内存的一致性问题。一个处理器上的线程修改了某数据,而在另一处理器上的线程可能仍然使用着该数据在专用cache中的老值,这就是可见性出了问题。解决办法是令该数据为volatile属性,或者读该数据之前执行内存屏障。

乱序执行与编译器重排序优化的比较

C与C++语言中,volatile关键字意图允许内存映射的I/O操作。这要求编译器对此的数据读写按照程序中的先后顺序执行,不能对volatile内存的读写重排序。因此关键字volatile并不保证是一个内存屏障。

对于Visual Studio 2003,编译器保证对volatile的操作是有序的,但是不能保证处理器的乱序执行。因此,可以使用InterlockedCompareExchange或InterlockedExchange函数。

对于Visual Studio 2005及以后版本,编译器对volatile变量的读操作使用acquire semantics,对写操作使用release semantics。 [1]

相关文章
|
8月前
|
存储 缓存 Java
【并发编程的艺术】详解指令重排序与数据依赖
本章详细描述了指令重排序的场景,条件,以及数据依赖、控制依赖对指令重排序的影响。总结如下: 单线程程序,对存在控制依赖的操作执行重排序,不会改变执行结果;但在多线程程序中,对存在控制依赖的操作执行重排序,可能会改变程序的执行结果!这就是多线程执行时出现并发问题的根本原因,切记。
88 0
|
1月前
|
缓存
内存屏障笔记分享
【4月更文挑战第3天】内存屏障笔记分享
41 5
|
3月前
|
Java 编译器 开发者
为什么代码会重排序
在并发编程中,重排序是一项为了提高性能而进行的优化策略。理解重排序的原理和可能引发的问题对于编写高效且正确的多线程代码至关重要。Java提供了一些机制,如内存屏障,来帮助开发者在多线程环境下保持程序的正确性和可靠性。
18 0
|
4月前
|
Java 编译器 程序员
【面试问题】什么是指令重排?
【1月更文挑战第27天】【面试问题】什么是指令重排?
|
5月前
|
Java
6.什么是内存屏障?具有什么作用?
6.什么是内存屏障?具有什么作用?
53 0
6.什么是内存屏障?具有什么作用?
|
9月前
|
缓存 安全 Java
volatile底层的实现原理:volatile关键字的作用、内存模型、JMM规范和CPU指令
volatile底层的实现原理:volatile关键字的作用、内存模型、JMM规范和CPU指令
124 0
|
存储 缓存 Java
看完这篇,还不懂JAVA内存模型(JMM)算我输
看完这篇,还不懂JAVA内存模型(JMM)算我输
127 0
看完这篇,还不懂JAVA内存模型(JMM)算我输
|
编译器
|
缓存 编译器 C语言
指令重排序与内存屏障
指令重排序与内存屏障
240 0
指令重排序与内存屏障