2

我正在使用线程,我对如何允许编译器优化以下代码有疑问:

void MyClass::f(){
    Parent* p = this->m_parent;
    this->m_done = true;
    p->function();
}

非常重要的是p(在堆栈上或在寄存器中)用于调用函数而不是this->m_parent. 因为如果它碰巧运行它的清理过程(我已经因此而发生实际崩溃),那么它可能会从另一个线程中删除,在这种情况下m_done可能true包含垃圾,但线程堆栈/寄存器将是完整的。thism_parent

我在 GCC/Linux 上的初始测试表明我没有竞争条件,但我想知道其他编译器是否也会出现这种情况?

这是gulp volatile的情况吗?我已经查看了 C++ 中的“易失性”阻止了哪些优化?在这个多线程 C++ 代码中是否需要“易失性”?但我不觉得他们中的任何一个都适用于我的问题。

我对此感到不安,因为我不确定编译器可以在这里做什么。我看到以下情况:

  • 没有/有益的优化,指针this->m_parent存储在堆栈/寄存器中,这个值稍后用于调用function()这是想要的行为。
  • 编译器删除pthis->m_parent偶然在寄存器中可用,编译器使用它来调用function()将起作用,但在编译器之间不可靠。这很糟糕,因为它可能会暴露移动到不同平台/编译器版本的错误。
  • 编译器在调用 之前删除p并读取,这会产生我不能拥有的竞争条件。this->m_parentfunction()

有人可以阐明编译器在这里允许做什么吗?

编辑

我忘了提到那this->m_done是一个std::atomic<bool>,我正在使用 C++11。

4

3 回答 3

2

m_done如果is ,此代码将像用 C++11 编写的那样完美运行std::atomic<bool>。的读取m_parent在写入之前排序,该写入将与另一个线程中m_done的假设读取同步,该线程在假设写入之前排序。总之,这意味着该标准保证该线程的读取发生在另一个线程的写入之前。m_donem_parentm_parent

于 2013-07-12T16:25:00.667 回答
1

您可能会遇到重新排序问题。检查内存屏障以解决此问题。放置它,以便 p 的加载和 m_done 的设置完全按照该顺序完成(将它放在两个指令之间),你应该没问题。

实现在 C++11 和 boost 中可用。

于 2013-07-12T16:19:03.863 回答
-1

嗯,当你在它的一个成员函数中时,其他一些线程可能会从你下面删除对象?未定义的行为。干净利落。

于 2013-07-12T16:30:56.430 回答