C++ 线程不检测全局变量变化

标签 c++ multithreading global-variables mutex

我有 2 个线程监视同一个全局 state,如果 state.shutdown 变为 false,线程 run() 应该返回。代码如下。

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>

using namespace std;

struct State {
    bool shutdown = false;

    ~State() {
        shutdown = true;
    }
};

State state;

#define CHECK_SHUTDOWN     \
  {                        \
    std::cout << (state.shutdown ? " SHUTDOWN " : " NOSHUT ") << typeid(*this).name() << std::endl; \
    if (state.shutdown) {  \
        return;            \
    }                      \
  }

class Mythread {
public:
    void join();
    void run();
    void launch();
    std::thread self_thread;
};

void Mythread::run() {
    while(1) {
        CHECK_SHUTDOWN
    }
}

void Mythread::join() {
    if (self_thread.joinable()) {
        self_thread.join();
    }
}

void Mythread::launch() {
    self_thread = std::thread(&Mythread::run, this);
}

std::mutex mtx;
void shut() {
    std::lock_guard<std::mutex> lock(mtx);   
    state.shutdown = true;
}

int main()
{
    Mythread thread1;
    Mythread thread2;

    thread1.launch();
    thread2.launch();

    std::this_thread::sleep_for(std::chrono::milliseconds(1000));


    //state.shutdown = true;
    shut(); //This makes no difference with the line above

    std::this_thread::sleep_for(std::chrono::milliseconds(100));

    thread1.join();
    thread2.join();


    return 0;
}

但是,即使我手动将 state.shutdown 设置为 true,线程也永远无法检测到它。我有这样的打印:

 NOSHUT 8Mythread                                                                                                
 NOSHUT 8Mythread                                                                                                
 NOSHUT 8Mythread                                                                                                                                                                                                                

...Program finished with exit code 0                                                                             
Press ENTER to exit console. 

最后。我也很困惑,因为从未返回 run() 函数,线程连接应该挂起。但是线程可以成功加入。

如有任何帮助,我们将不胜感激!

最佳答案

你有一个 data race关机时。

When an evaluation of an expression writes to a memory location and another evaluation reads or modifies the same memory location, the expressions are said to conflict. A program that has two conflicting evaluations has a data race [...]

shut()你设置了 shutdown标记使用互斥锁,但检查是在没有互斥锁的情况下执行的(并且 State 析构函数也不使用互斥锁)。因此,您在非原子变量上有冲突的操作(读 + 写),没有正确的发生在关系之前。这是导致未定义行为的数据竞争。

简单的解决方案是制作shutdown一个std::atomic<bool> ,那么您甚至不需要互斥锁来设置标志。

有关数据竞争和 C++ 内存模型的更多详细信息,我可以推荐我与人合着的这篇论文:Memory Models for C/C++ Programmers

关于C++ 线程不检测全局变量变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62077786/

相关文章:

c++ - 与非常量引用参数交换

C++容器/数组/元组一致访问接口(interface)

c++ - 在类(class)中如何访问类(class)成员指向的地址?

c# - 独占锁与线程纤程

C++:对于这种情况,是否有更好的替代方法来使用静态属性?

javascript - 跨多个页面设置javascript全局变量

c++ - DLL 中的全局指针

c++ - 用于函数调用捕获的 Lua 元表

python - 如何在 Python 3 中引用线程?

c++ - 访问boost线程对象的成员变量