C++ 线程不检测全局变量变化
C++ Thread does not detect global variable change
我有 2 个线程监视同一个全局 state
,如果 state.shutdown
变成 false
,线程 run()
应该 return。代码如下。
#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()
函数从未被 returned,线程连接应该挂起。但是线程可以成功加入。
如有任何帮助,我们将不胜感激!
您 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
我有 2 个线程监视同一个全局 state
,如果 state.shutdown
变成 false
,线程 run()
应该 return。代码如下。
#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()
函数从未被 returned,线程连接应该挂起。但是线程可以成功加入。
如有任何帮助,我们将不胜感激!
您 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