ARM中屏障(DSB、DMB、ISB)的实际使用案例

ARM中屏障(DSB、DMB、ISB)的实际使用案例,arm,barrier,Arm,Barrier,我知道DSB、DMB和ISB是防止指令重新排序的障碍。 我也能找到很多很好的解释,但很难想象我会使用它们 此外,从开源代码中,我不时看到这些障碍,但很难理解为什么要使用它们。举个例子,在Linux内核3.7 tcp_rcv_synsent_state_进程函数中,有一行代码如下: if (unlikely(po->origdev)) sll->sll_ifindex = orig_dev->ifindex; else

我知道DSB、DMB和ISB是防止指令重新排序的障碍。 我也能找到很多很好的解释,但很难想象我会使用它们

此外,从开源代码中,我不时看到这些障碍,但很难理解为什么要使用它们。举个例子,在Linux内核3.7 tcp_rcv_synsent_state_进程函数中,有一行代码如下:

    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);
if(不太可能(采购订单->原始版本))
sll->sll\u iIndex=原始开发->iIndex;
其他的
sll->sll_iIndex=dev->iIndex;
smp_mb();

如果(po->tp_version通常,在必须确保内存访问按特定顺序进行的情况下,您需要使用内存屏障。这可能是出于多种原因,通常是两个或多个进程/线程或硬件组件访问同一内存结构时需要使用,必须保持一致

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

struct dma_control {
  u32 owner;
  void * data;
  u32 len;
};
所有者通常被设置为所有者CPU或所有者硬件,以指示允许两个参与者中的谁使用该结构

改变这一点的代码通常是这样的

dma->data = data;
dma->len  = length;
smp_mb();
dma->owner = OWNER_HARDWARE;
因此,数据和len总是在所有权转移到DMA硬件之前设置的。否则,引擎可能会得到过时的数据,如指针或未更新的长度,因为CPU重新排序了内存访问


运行在不同内核上的进程或线程也是如此。它们可以以类似的方式进行通信。

对不起,我不会像你所问的那样给你一个直截了当的例子,因为你已经在浏览Linux源代码了,你有很多源代码可以使用,而且它们似乎没有任何帮助。这一点也不丢脸——eve一个头脑清醒的人至少一开始会被内存访问顺序问题弄糊涂:)

如果您主要是一名应用程序开发人员,那么您完全有可能不需要太担心它——无论您使用什么并发框架,都会为您解决这个问题

如果您主要是一名设备驱动程序开发人员,那么很容易找到示例—只要您的代码中有一个依赖项在执行其他访问(重新启用中断,启动DMA事务)之前对先前的访问产生了影响(清除中断源,编写DMA描述符)

如果您正在开发一个并发框架(或调试一个),您可能需要进一步阅读这个主题——但是您的问题只是表面上的好奇,而不是眼前的需要? 如果您正在开发自己的在线程之间传递数据的方法,而不是基于并发框架提供的原语,那么无论出于何种目的,这都是一个并发框架

保罗·麦肯尼(Paul McKenney)写了一篇优秀的论文,论述了对内存屏障的需求以及它们对处理器的实际影响:

如果这有点过于硬核的话,我写了一个由三部分组成的博客系列,它稍微轻一些,最后以一个特定于ARM的视图结束。第一部分是

但是,如果您特别关注的是示例列表,尤其是ARM体系结构,那么您可能会做得比这糟糕得多

extra-extra-light程序员的视图和不完全正确的架构版本是:

  • DMB-每当一个内存访问需要对另一个内存访问进行排序时
  • DSB—在程序执行之前,每当需要完成内存访问时
  • ISB—每当指令获取需要在程序中的某个点之后显式进行时,例如在内存映射更新之后或在编写要执行的代码之后。(在实践中,这意味着“此时扔掉任何预取指令”。)

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

      DMB尤其防止围绕DMB的内存访问重新排序。如果没有DMB,处理器可以在释放自旋锁后将存储重新排序到受自旋锁保护的内存。或者,处理器可以在自旋锁被实际锁定之前,或者在自旋锁被其他上下文锁定时,读取由自旋锁保护的内存


      unixsmurf已经指出了这一点,但我也会向你们指出。它提供了一些很好的例子,说明了应该在何处以及为什么使用屏障。

      这个问题是最近的一个例子:《Cortex程序员指南》也有一节介绍了屏障(11.2)。有可能有帮助的信息。很好的解释。不过,我还是忍不住对这3个说明产生了一点疑问。基本上,您编写的是:DMB:确保完成上述代码。DSB:确保上述代码已完成。ISB:确保上述代码已完成。(我应该阅读您提供的链接。)不过,“volatile”不会告诉编译器保证指令顺序吗?(最终插入上述命令之一等)@Illishar:volatile会影响编译器生成指令的顺序,是的。当这些指令的结果在无序和/或多cpu系统中保证架构一致时,这些指令会产生影响。保罗·麦肯尼(Paul McKenney)的论文是列出的资源中最完整的一篇,值得花些时间阅读。至于说明书,说明书上不是这么说的。当进入并发世界时,要习惯于必须非常注意语义。