ARM中屏障(DSB、DMB、ISB)的实际使用案例
我知道DSB、DMB和ISB是防止指令重新排序的障碍。 我也能找到很多很好的解释,但很难想象我会使用它们 此外,从开源代码中,我不时看到这些障碍,但很难理解为什么要使用它们。举个例子,在Linux内核3.7 tcp_rcv_synsent_state_进程函数中,有一行代码如下: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
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)的论文是列出的资源中最完整的一篇,值得花些时间阅读。至于说明书,说明书上不是这么说的。当进入并发世界时,要习惯于必须非常注意语义。