【问题标题】:Compiler reordering around mutex boundaries?编译器围绕互斥边界重新排序?
【发布时间】:2010-04-22 22:38:45
【问题描述】:

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

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

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

【问题讨论】:

  • 我想指出,尽管编译器重新排序处理器也可以重新排序指令(请参阅缓存一致性)。 Mutex 实现也插入了内存屏障,因此它绝对是运行时安全的。

标签: c++ compiler-optimization memory-barriers


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 正确。代码运动编译器将拥有一个关于程序如何运行及其数据/操作依赖关系的静态分析模型,并将保留这些依赖关系。
    • 严格来说,_field 变量和对 LockMutex 或 UnlockMutex 的调用之间没有任何依赖关系,因此保留依赖关系在这里没有帮助。
    【解决方案3】:

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

    【讨论】:

    • 谢谢。您是否有说明编译器重新排序在内联函数边界处停止的文档的链接?
    【解决方案4】:

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

    pthread_mutex_lock( &mx ) + foo() + pthread_mutex_unlock( &mx );
    

    【讨论】:

      【解决方案5】:

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

      【讨论】:

        【解决方案6】:

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

        【讨论】:

        • 如果变量是本地的,不是易失的,并且没有指针或引用,其他线程不能访问它。因此,就获取互斥体而言,存储发生在函数调用之前、之后或之间,或者它是否从未发生都无关紧要。
        • @Michael Burr,这不是我说的吗?如果编译器足够复杂,它可能会确定局部变量加载/存储可以安全地重新排序;它是否可能取决于优化器设置。我正在超越问题的范围,很明显变量是 not 本地的。如所问,它属于我的第一句话-编译器无法知道 LockMutex 或 UnlockMutex 的副作用,因此无法重新排序。
        • 我没有不同意;我以为我在澄清答案末尾似乎不确定的事情。如果它是这样出现的,我并不是想让它听起来有争议。
        猜你喜欢
        • 2023-03-29
        • 1970-01-01
        • 1970-01-01
        • 2015-10-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-07
        相关资源
        最近更新 更多