一个线程设置成员而另一个线程遍历它 - 这个线程不安全吗?

Cha*_*onX 2 c++ optimization multithreading

我刚刚在代码库中发现了以下构造(在示例中简化):

class SomeClass
{
  public:
    void setKeepGoing(bool b) { m_keepGoing = b; }
    void setDoAdditionalStuff(bool b) { m_doAdditionalStuff = b; }
    void someLoop()
    {
        while(m_keepGoing) 
        {
            //Do something
            bool doMore = m_doAdditionalStuff;
            if (doMore)
                //Do more things
        }  
    }

  private:
    bool m_keepGoing;
    bool m_doAdditionalStuff;
}
Run Code Online (Sandbox Code Playgroud)

有多个线程,一个呼叫,someLoop()而其他线程呼叫setKeepGoing()和/或setDoAdditionalStuff().

现在我的直觉是,这是非常不安全的线程.编译器可以很好地优化m_doAdditionalStuff循环内部的读取(因为它没有在那里改变),甚至m_keepGoing(因为它也没有在那里改变)有效地导致代码表现如下:

void someLoop()
{
    if (!m_keepGoing)
        return;
    bool doMore = m_doAdditionalStuff;
    while(true) 
    {
        //Do something
        if (doMore)
            //Do more things
    }  
}
Run Code Online (Sandbox Code Playgroud)

我的怀疑是否正确?

Jes*_*uhl 5

如果你有读者作者(或多个作者;除了读者之外的任何东西)在多个线程中访问同一个变量,你需要将该变量设为原子使用锁(或其他同步原语).否则,您将进行数据竞争,并且您的程序具有未定义的行为.


Nat*_*ica 5

你的怀疑是正确的.如果没有某种同步机制,您无法在多个线程中写入和读取相同的变量.这样做是数据竞争,是未定义的行为.

在这种情况下你可以做的是使用一个std::atomic<bool>for m_keepGoing,m_doAdditionalStuff这样你就可以进行同步.