假设我有自己的非内联函数LockMutex和UnlockMutex,它们正在使用一些正确的互斥锁 - 例如boost - inside。对于LockMutex和UnlockMutex的调用,编译器如何知道不重新排序其他操作?它不可能知道如何在其他编译单元中实现这些功能。
void SomeClass::store(int i)
{
LockMutex(_m);
_field = i; // could the compiler move this around?
UnlockMutex(_m);
}
ps:应该使用类的实例来保存锁以保证解锁。我把它留下来简化示例。
答案 0 :(得分:2)
通常,编译器不会移动代码,除非它确实知道这样做不会影响运行时行为。
答案 1 :(得分:2)
我不可能知道如何在其他编译单元中实现这些功能。
这是关键 - 因为编译器不能(通常)知道函数调用的实现,所以它不能将存储移动到那些函数调用之外的_field
。
通常,由于_field
可以在SomeClass::store()
之外访问(它不是本地的),编译器无法知道它是否被外部函数修改,因此它必须执行存储到函数调用序列点之间的_field
。
底层硬件平台可能需要以内存屏障或缓存刷新的形式引起注意,以处理硬件中发生的缓存或乱序操作。如果需要,平台的互斥API实现将处理这些问题。
答案 2 :(得分:1)
在编写时,如果函数不是内联函数,编译器将不会移动变量赋值,因为调用可能与_field变量无关,但它必须保持严格的调用顺序。但是,如果编译器决定内联调用,我认为它会将它们视为独立代码块,也就是说,它只会在同一代码单元(内联函数本身)中重新排序指令,但不会对以下内容或之前的内容重新排序代码(分配给_field变量)。
答案 3 :(得分:1)
你是对的,代码是正确和安全的。我确实想到了一个“代码笑话”。
pthread_mutex_lock( &mx ) + foo() + pthread_mutex_unlock( &mx );
答案 4 :(得分:0)
如果编译器这样做,那将是一个糟糕的编译器。 ; - )
答案 5 :(得分:0)
如果编译器无法保证函数调用不会产生会修改调用之间变量的副作用,则无法移动代码。如果变量是局部变量并且您从未接受过引用或者创建了指向它的指针,则编译器可能会认为它是安全的。我不知道。