ARM实际使用障碍案例(DSB,DMB,ISB)

jae*_*ong 22 arm barrier

据我所知,DSB,DMB和ISB是阻止指令重新排序的障碍.我也可以为每一个找到很多非常好的解释,但很难想象我必须使用它们的情况.

另外,从开源代码中,我不时会看到这些障碍,但很难理解它们的使用原因.举个例子,在Linux内核3.7 tcp_rcv_synsent_state_process函数中,有一行如下:

    if (unlikely(po->origdev))
            sll->sll_ifindex = orig_dev->ifindex;
    else
            sll->sll_ifindex = dev->ifindex;

    smp_mb();

    if (po->tp_version <= TPACKET_V2)
            __packet_set_status(po, h.raw, status);
Run Code Online (Sandbox Code Playgroud)

其中smp_mb()基本上是DMB.你能举一些现实生活中的例子吗?这将有助于更多地了解障碍.

uni*_*urf 35

对不起,不要像你要问的那样给你一个直截了当的例子,因为你已经在查看Linux源代码了,你有很多可以解决的问题,而且它们似乎没有帮助.没有羞耻 - 每个理智的人至少最初都会被内存访问排序问题弄糊涂:)

如果您主要是应用程序开发人员,那么您有可能不必过多担心它 - 无论您使用什么并发框架都将为您解决它.

如果您主要是设备驱动程序开发人员,则可以非常直接地找到示例 - 只要在执行某些其他访问之前,您的代码中的某个依赖项对前一次访问产生了影响(清除了中断源,写入了DMA描述符) (重新启用中断,启动DMA事务).

如果您正在开发并发框架(或调试一个),您可能需要更多地阅读该主题 - 但您的问题表明一种肤浅的好奇心,而不是直接需要?如果您正在开发自己的方法来在线程之间传递数据,而不是基于并发框架提供的原语,那么对于所有意图和目的而言,这是一个并发框架.

Paul McKenney撰写了一篇关于内存障碍需求的优秀论文,以及它们在处理器中实际产生的影响:内存障碍:软件黑客的硬件视图

如果这有点太硬了,我写了一个由三部分组成的博客系列,它更轻巧一些,并以特定于ARM的视图结束.第一部分是内存访问排序 - 介绍.

但是如果它是你所追求的具体列表,特别是对于ARM架构,你可能会比Barrier Litmus Tests和Cookbook做得更糟.

额外的轻量级程序员的视图并不完全在架构上正确的版本是:

  • DMB - 每当内存访问需要关于另一个内存访问的排序时.
  • DSB - 在程序执行进行之前需要完成内存访问.
  • ISB - 每当指令读取需要在程序中的某个点之后显式发生时,例如在存储器映射更新之后或在写入要执行的代码之后.(实际上,这意味着"此时丢掉任何预取的指令".)

  • @Illishar:易失性会影响编译器生成指令的顺序,是的。这些指令会影响何时保证这些指令的结果在乱序和/或多 CPU 系统中保持架构一致。Paul McKenney 的论文是列出的资源中最完整的一篇,非常值得花一些时间阅读。至于说明,这“不是”描述所说的。当进入并发世界时,要习惯于必须对语义给予“大量”关注。 (5认同)

Nic*_*rth 5

通常,在必须确保按特定顺序进行内存访问时,需要使用内存屏障.出于多种原因可能需要这样做,通常在两个或多个进程/线程或硬件组件访问相同的内存结构时需要这样做,这必须保持一致.

它经常用于DMA传输.一个简单的DMA控制结构可能如下所示:

struct dma_control {
  u32 owner;
  void * data;
  u32 len;
};
Run Code Online (Sandbox Code Playgroud)

通常将所有者设置为OWNER_CPU或OWNER_HARDWARE,以指示允许两个参与者中的哪个参与者使用该结构.

改变这个的代码通常会像这样

dma->data = data;
dma->len  = length;
smp_mb();
dma->owner = OWNER_HARDWARE;
Run Code Online (Sandbox Code Playgroud)

因此,在所有权转移到DMA硬件之前,始终设置len数据.否则,引擎可能会获得过时的数据,例如未更新的指针或长度,因为CPU重新排序了内存访问.

对于在不同核上运行的进程或线程也是如此.可以以类似的方式进行通信.


rsa*_*xvc 5

屏障要求的一个简单示例是自旋锁。如果您使用比较和交换(或 ARM 上的 LDREX/STREX)实现自旋锁并且没有屏障,则允许处理器推测性地从内存加载值并将计算值延迟存储到内存,并且这些都不需要发生按照指令流中加载/存储的顺序。

DMB 特别防止围绕 DMB 的内存访问重新排序。如果没有 DMB,处理器可能会在释放自旋锁后重新排序对受自旋锁保护的内存的存储。或者,处理器可以在自旋锁实际锁定之前或在它被不同的上下文锁定时读取受自旋锁保护的内存。

unixsmurf 已经指出了这一点,但我还会向您指出Barrier Litmus Tests 和 Cookbook。它有一些很好的例子说明在哪里以及为什么应该使用障碍。