简体   繁体   English

编译器内存屏障和互斥锁

[英]compiler memory barrier and mutex

posix standard says that things like mutex will enforce a memory sync. posix标准说像mutex这样的东西会强制执行内存同步。 However, the compiler may reorder the memory access. 但是,编译器可能会重新排序内存访问。 Say we have 说我们有

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

It might be changed to code below by compiler reordering, right? 可能会通过编译器重新排序将其更改为下面的代码,对吗?

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

So how can mutex sync the memory access? 那么互斥量如何同步内存访问? To be more precise, how do compilers know that reordering should not happen across lock/unlock? 更确切地说,编译器如何知道重锁不应该在锁定/解锁时发生?

actually here for single thread aspect, ready assignment reorder is totally safe since ready is not used in function call lock(mutex). 实际上这里对于单线程方面,就绪分配重新排序是完全安全的,因为就绪不用于函数调用锁(mutex)。

EDITED: So if function call is something that compiler will not get across, can we regard it as a compiler memory barrier like 编辑:因此,如果函数调用是编译器无法解决的问题,我们可以将其视为编译器内存屏障

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

General answer is that your compiler should support POSIX if you want to use it for POSIX targets, and that support means it should know to avoid reordering across lock and unlock. 一般的答案是,如果你想将它用于POSIX目标,你的编译器应该支持POSIX,而这种支持意味着它应该知道避免重新排序锁定和解锁。

That said, this kind of knowledge is commonly achieved in a trivial way: compiler would not reorder access to (non-provably-local) data across a call to an external function which may use or modify them. 也就是说,这种知识通常是以一种微不足道的方式实现的:编译器不会通过调用可能使用或修改它们的外部函数来重新排序对(不可证实 - 本地)数据的访问。 It should have known something special about lock and unlock to be able to reorder. 应该知道关于lockunlock一些特殊内容,以便能够重新排序。

And no, it's not that simple as "a call to global function is always a compiler barrier" -- we should add "unless the compiler knows something specific about that function". 不,它并不是那么简单,因为“对全局函数的调用总是一个编译器障碍” - 我们应该添加“除非编译器知道关于该函数的具体内容”。 It does really happen: eg pthread_self on Linux (NPTL) is declared with __const__ attribute, allowing gcc to reorder across pthread_self() calls, even eliminating unnecessary calls altogether. 确实发生了这种情况:例如Linux上的pthread_self (NPTL)声明为__const__属性,允许gccpthread_self()调用中重新排序,甚至完全消除不必要的调用。

We can easily imagine a compiler supporting function attributes for acquire/release semantics, making lock and unlock less than a full compiler barrier. 我们可以很容易地想象一个编译器支持获取/释放语义的函数属性,使得lockunlock不是一个完整的编译器障碍。

Compilers will not reorder things where it is not clear that it is safe. 编译器不会在不清楚它是否安全的情况下重新排序。 In your "what if" example, you are not proposing a reordered memory access, you're asking what if the compiler totally changes the code ordering -- and it won't. 在你的“假设”示例中,你没有提出重新排序的内存访问,你问的是编译器是否完全改变了代码排序 - 而且它不会。 Something the compiler might do is change the order of actual memory reads/writes but not function calls (with or without respect to those memory accesses). 编译器可能做的事情是改变实际内存读/写的顺序,但不改变函数调用(有或没有那些内存访问)。

An example of where the compiler might reorder memory access... lets say you have this code: 编译器可能重新排序内存访问的示例...假设您有以下代码:

a = *pAddressA;
b = *pAddressB;

and lets consider the case where the value of pAddressB is in a register while pAddressA is not. 并且考虑pAddressB的值在寄存器中而pAddressA不在的情况。 It's fair game for the compiler to read address B first, then move the value of pAddressA into that same register so that the new location can be received. 编译器首先读取地址B,然后将pAddressA的值移动到同一个寄存器中以便可以接收新位置,这是公平的游戏。 If there happens to be a function call between these accesses, the compiler cannot do this. 如果在这些访问之间碰巧发生了函数调用,则编译器无法执行此操作。

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

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