我遇到了一些类,它们的唯一功能是连续不断地执行一些工作,并且它们的设计使得它们定义了一个公共方法,可以调用该方法以在新的std::thread
中调用该成员函数。我指的是这样的东西:
class ThreadLooper {
public:
ThreadLooper(const std::string &thread_name)
: thread_name_{thread_name}, loopCounter_{0} {}
~ThreadLooper() {
cout << thread_name_ << ": destroyed and counter is " << loopCounter_
<< std::endl;
}
void run() {
std::thread([this]() { detachedThreadLoop(); }).detach();
}
private:
void detachedThreadLoop() {
cout << thread_name_ << ": detachedThreadLoop() started running"
<< std::endl;
while (true) {
using namespace std::literals::chrono_literals;
std::this_thread::sleep_for(2s);
++loopCounter_;
cout << thread_name_ << ": counter is " << loopCounter_ << std::endl;
}
}
std::string thread_name_;
std::atomic_uint64_t loopCounter_;
};
int main() {
cout << "In main()" << std::endl;
{
ThreadLooper threadLooper{"looper1"};
threadLooper.run();
using namespace std::literals::chrono_literals;
std::this_thread::sleep_for(20s);
cout << "main() done sleeping, exiting block scope..." << std::endl;
}
while (true) {
using namespace std::literals::chrono_literals;
std::this_thread::sleep_for(20s);
cout << "main() woke up..." << std::endl;
}
return 0;
}
这似乎是因为在分离线程中运行的函数具有指向该实例的指针,但是可以继续在该实例的生命周期内运行,这很糟糕。我见过其他未分离线程的类,然后在析构函数中设置了一个标志,告诉线程循环退出,然后将线程加入析构函数中。似乎后者是执行此操作的正确方法,而前者则依赖于这样的事实:该类仅在程序实例存在的情况下才使用。这是正确的还是我错过了什么?
答案 0 :(得分:2)
是的,使用std::thread::detach
意味着您需要使用自己的方法来确保线程在使用的所有资源被销毁之前终止。
在这种情况下,当程序退出ThreadLooper
中的第一个块作用域时,main()
将调用未定义的行为。最好不要使用detach()
,然后std::thread
将调用std::terminate
,如果您忘记在线程(及其包含的对象)被销毁之前调用join()
。