互斥可以取代内存障碍

时间:2015-02-26 08:55:36

标签: memory linux-kernel mutex memory-barriers

我试图了解内存障碍并遇到了以下维基百科链接 http://en.wikipedia.org/wiki/Memory_barrier 这很好地解释了这个概念,但是如果在我们有mutex()锁定内存部分的系统中这是非常有用的,那就有了想法。

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

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

处理器#1

mutex_lock(a)
while (f == 0);
print x;
mutex_unlock(a)

处理器#2

mutex_lock(a)
x = 42;
f = 1;
mutex_unlock(a)

3 个答案:

答案 0 :(得分:7)

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

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

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

这两个概念之间存在关联:互斥体在没有至少部分内存障碍的情况下实际上是无用的。考虑这个例子:

mutex_lock(a);
x = x+1;
mutex_unlock(a);

锁定操作必须至少具有"获取"阻止x加载在获取锁之前出现的障碍。同样,"解锁"操作必须至少有一个"发布"阻止x锁存在锁定释放后出现的障碍。这就是锁定解锁对形成一个笼子,操作无法逃脱。 (虽然有时程序员会在重新排序导致操作将爬进笼子时感到惊讶!)

因此,锁定互斥锁并立即解锁它会起到内存屏障的作用,尽管它会强制执行串行执行,因此效率非常低。

答案 1 :(得分:3)

内存条通常用于使无序管道在内存访问方面处于明确定义的状态,因此与互斥锁的概念正交,后者通常是更高级别的多处理中的概念(与CPU指令的无序执行无关)。

答案 2 :(得分:3)

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

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

asm volatile("":::"memory")

以下是解释:

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