繁体   English   中英

编译器内存屏障和互斥锁

[英]compiler memory barrier and mutex

posix标准说像mutex这样的东西会强制执行内存同步。 但是,编译器可能会重新排序内存访问。 说我们有

lock(mutex);
setdata(0);
ready = 1;
unlock(mutex);

可能会通过编译器重新排序将其更改为下面的代码,对吗?

ready = 1;
lock(mutex);
setdata(0);
unlock(mutex);

那么互斥量如何同步内存访问? 更确切地说,编译器如何知道重锁不应该在锁定/解锁时发生?

实际上这里对于单线程方面,就绪分配重新排序是完全安全的,因为就绪不用于函数调用锁(mutex)。

编辑:因此,如果函数调用是编译器无法解决的问题,我们可以将其视为编译器内存屏障

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

一般的答案是,如果你想将它用于POSIX目标,你的编译器应该支持POSIX,而这种支持意味着它应该知道避免重新排序锁定和解锁。

也就是说,这种知识通常是以一种微不足道的方式实现的:编译器不会通过调用可能使用或修改它们的外部函数来重新排序对(不可证实 - 本地)数据的访问。 应该知道关于lockunlock一些特殊内容,以便能够重新排序。

不,它并不是那么简单,因为“对全局函数的调用总是一个编译器障碍” - 我们应该添加“除非编译器知道关于该函数的具体内容”。 确实发生了这种情况:例如Linux上的pthread_self (NPTL)声明为__const__属性,允许gccpthread_self()调用中重新排序,甚至完全消除不必要的调用。

我们可以很容易地想象一个编译器支持获取/释放语义的函数属性,使得lockunlock不是一个完整的编译器障碍。

编译器不会在不清楚它是否安全的情况下重新排序。 在你的“假设”示例中,你没有提出重新排序的内存访问,你问的是编译器是否完全改变了代码排序 - 而且它不会。 编译器可能做的事情是改变实际内存读/写的顺序,但不改变函数调用(有或没有那些内存访问)。

编译器可能重新排序内存访问的示例...假设您有以下代码:

a = *pAddressA;
b = *pAddressB;

并且考虑pAddressB的值在寄存器中而pAddressA不在的情况。 编译器首先读取地址B,然后将pAddressA的值移动到同一个寄存器中以便可以接收新位置,这是公平的游戏。 如果在这些访问之间碰巧发生了函数调用,则编译器无法执行此操作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM