8

假设我有自己的非内联函数 LockMutex 和 UnlockMutex,它们在内部使用了一些适当的互斥锁 - 例如 boost。编译器如何知道不对 LockMutex 和 UnlockMutex 调用的其他操作重新排序?它不可能知道我将如何在其他编译单元中实现这些功能。

void SomeClass::store(int i)
{
  LockMutex(_m);
  _field = i;  // could the compiler move this around?
  UnlockMutex(_m);
}

ps:一个应该使用类的实例来持有锁以保证解锁。为了简化示例,我忽略了这一点。

4

6 回答 6

3

它不可能知道我将如何在其他编译单元中实现这些功能。

这是关键——因为编译器(通常)不知道函数调用的实现,它不能将存储移动到_field这些函数调用之外。

通常,由于_field可以在外部访问SomeClass::store()(它不是本地的),编译器无法知道它是否被外部函数修改,因此它必须_field在函数调用序列点之间执行存储。

底层硬件平台可能需要以内存屏障或缓存刷新的形式进行一些关注,以处理硬件中发生的缓存或乱序操作。如有必要,互斥 API 的平台实现将处理这些问题。

于 2010-04-23T00:29:18.790 回答
2

一般来说,编译器不会移动代码,除非它确定这样做不会影响运行时行为。

于 2010-04-22T22:49:16.560 回答
1

如其所写,如果函数不是内联的,编译器将不会移动变量分配,因为调用可能与 _field 变量无关,但它必须保持调用的严格顺序。但是,如果编译器决定内联调用,我认为它会将它们视为独立代码块,也就是说,它只会重新排序同一代码单元(内联函数本身)内的指令,而不是后面或前面的代码(分配给 _field 变量)。

于 2010-04-22T22:57:41.703 回答
1

您是对的,该代码是正确且安全的。不过,我确实想到了一个“代码笑话”。

pthread_mutex_lock( &mx ) + foo() + pthread_mutex_unlock( &mx );
于 2010-04-22T22:58:21.400 回答
0

如果编译器这样做,那将是一个糟糕的编译器。;-)

于 2010-04-22T22:44:26.047 回答
0

如果编译器不能保证函数调用不会产生会修改调用之间变量的副作用,它就不能移动代码。如果该变量是一个局部变量并且您从未获取过引用或创建指向它的指针,编译器可能会认为它可以安全移动;我不知道。

于 2010-04-22T22:50:59.720 回答