互斥可以取代内存障碍

pku*_*arn 0 memory mutex linux-kernel memory-barriers

我试图了解内存障碍并且遇到了下面的维基百科链接 http://en.wikipedia.org/wiki/Memory_barrier 这很好地解释了这个概念,但有想法,如果这对我们有mutex()锁定的系统真有帮助记忆部分.

使用维基百科中提到的相同代码,以下方法是否会使用互斥锁解决问题?

[注意:函数名称并非特定于任何编程语言,仅用于简单起见]

处理器#1

mutex_lock(a)
while (f == 0);
print x;
mutex_unlock(a)
Run Code Online (Sandbox Code Playgroud)

处理器#2

mutex_lock(a)
x = 42;
f = 1;
mutex_unlock(a)
Run Code Online (Sandbox Code Playgroud)

Arc*_*son 8

内存屏障保证先前指令的所有可见效果在任何后续指令之前都可观察到.可能重新排序观察到的效果顺序的事情是:

  • 编译器(通过重新排序说明)
  • 无序管道
  • 具有宽松内存一致性的缓存系统(几乎所有在现代系统上)

互斥锁保证一次只有一个线程持有互斥锁.

这两个概念之间存在关联:互斥体实际上没用,至少没有部分内存障碍.考虑这个例子:

mutex_lock(a);
x = x+1;
mutex_unlock(a);
Run Code Online (Sandbox Code Playgroud)

锁定操作必须至少具有"获取"屏障,以防止在获取锁定之前出现x的负载.同样,"解锁"操作必须至少具有"释放"屏障,以防止在释放锁之后出现x的存储.这就是锁定解锁对形成一个笼子,操作无法逃脱.(虽然有时会导致重新排序操作时,抓取程序员都惊讶笼子!)

因此,锁定互斥锁并立即解锁它可以充当内存屏障,尽管这是一个非常低效的因为它强制执行串行执行.


ska*_*hal 6

内核中的互斥锁和其他锁在内部使用屏障来确保代码按照预期的确切顺序运行。在编译器中使用优化时,您永远不应该假设指令将以与源代码中写入的顺序完全相同的顺序执行。编译器可能会以这种方式重新排序汇编语言指令,以优化寄存器的使用方式。此外,现代 CPU 通常并行执行多个指令,并且可能会重新排序内存访问。这些类型的重新排序可以大大加快程序速度。但可能会导致意外的输出!

因此,MEMORY BARRIER原语确保对应于放置在原语之前的C语句的汇编语言指令不会被编译器与对应于放置在原语之后的C语句的汇编语言指令混合。在linux中barrier()宏是:

asm volatile("":::"memory")
Run Code Online (Sandbox Code Playgroud)

解释如下:

  1. asm指令告诉编译器插入汇编语言片段
  2. volatile 关键字禁止编译器将 asm 指令与程序的其他指令重新组合
  3. memory 关键字强制编译器假设 RAM 中的所有内存位置都已被汇编语言指令更改;因此,编译器无法使用asm指令之前存储在CPU寄存器中的内存位置的值来优化代码