内联替换会导致多线程代码中的无限循环吗?

请注意:这只是出于好奇而提出的问题,与编写更好的多线程代码无关。当然,我不会也不会在实际项目中编写这样的代码。

添加关键字时可能会发生内联替换inline。所以我很好奇。

假设我们有这样的代码:

static bool done = false;

inline void setDone(bool newState) {
    done = newState;
}

inline bool getDone() {
    return done;
}

void someWorkerThreadJob() {
    // Accessing without any lock/atomic/volatile
    while (getDone() == false) {
    }
}

可以someWorkerThreadJob()像下面这样编译并进入无限循环吗?

void someThreadJob() {
    while (done == false) {
    }
}

这也将我引向了下一个问题。类中的gettersetter怎么样?在类中定义的成员函数是隐式的inline,所以我认为可能会发生内联替换,因此同样的问题。这样对吗?

回答

done必须在线程之间并行和同步保护对的访问。否则,处理器或编译器会产生/执行不正确的指令序列。您当前的程序格式不正确。

您面临的问题是done可以缓存在 L1 CPU 缓存中(取决于处理器),或者编译器可以优化对done全局变量的访问(通常通过将其放在寄存器中,尽管许多编译器实际上并没有这样做)。

您需要使用原子指令互斥锁/锁(或任何同步机制),以便done在修改时可以被其他线程看到。使用原子指令,编译器生成适当的内存栅栏,不放入done寄存器或/和生成同步通信总线的指令(例如在 x86_64 上)。

欲了解更多信息,你可以给看看缓存一致性协议,如MOESI,看看如何与原子能指令的x86交易。

在这种情况下,主流编译器(如 GCC 和 Clang)实际上将代码优化为无操作指令(这在 C++ 标准中是完全合法的),主要是由于staticinline关键字帮助编译器。情况并非如此std::atomic


以上是内联替换会导致多线程代码中的无限循环吗?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>