如何解决C++ 在析构函数中杀死一个线程
我有一个类,它启动另一个线程,以恒定的时间间隔访问它的一些数据。这意味着我有两个线程访问相同的数据(原始线程和新创建的线程)。这引入了对互斥锁的需求。一切顺利,直到类的析构函数被调用(在程序结束时)并且内存位置不再有效。此时新线程尝试访问数据并得到访问冲突错误(显然)。
我想做的是在析构函数中停止线程,或者在线程“注意到”类实例已被销毁时停止。
这里是简化的线程代码(为简洁起见使用 typedef):
void myClass::StartThread() {
auto threadFunc = [&,this]() {
while (true) {
time_point Now = steady_clock::Now();
if (chro::duration_cast<chro::milliseconds>(Now - this->m_lastSeedTime).count() > INTERVAL) {
std::lock_guard<std::mutex> lockGuard(this->m_mut);
this->m_lastSeedTime = Now;
this->accessData();
}
}
};
std::thread thread(threadFunc);
thread.detach();
当然,如果我只是以某种明显的方式处理不当,也请告诉我。
解决方法
如果你想让一个线程死掉,你应该要求它退出。这是干净利落的唯一可靠方法。
只要改变
while (true)
到
while(this->keepRunning)
并适当地同步它。要么不要分离线程(以便析构函数可以加入它),要么为线程添加某种方式来表明它已退出(以便析构函数可以等待它)。
哦,线程应该休眠而不是旋转。在这种情况下,如果您不希望析构函数也被阻塞,您需要某种方式来中断睡眠:对睡眠的条件变量使用定时等待使这变得容易。
,@Useless 的回答是正确的。以下是您的具体操作方法:
class myClass{
...
private:
std::thread m_thread;
std::atomic_bool m_keepRunning{true};
....
};
void myClass::StartThread() {
auto threadFunc = [&,this]() {
while (m_keepRunning) {
time_point now = steady_clock::now();
if (chro::duration_cast<chro::milliseconds>(now - this->m_lastSeedTime).count() > INTERVAL) {
std::lock_guard<std::mutex> lockGuard(this->m_mut);
if(!m_keepRunning) break; // destructor called,don't access data
this->m_lastSeedTime = now;
this->accessData();
}
}
};
m_thread = std::thread(threadFunc);
}
myClass::~myClass()
{
m_keepRunning = false;
m_mutex.unlock(); // make sure we don't wait in the loop for the lock
if(m_thread.joinable()) m_thread.join();
// do other cleaning
}
还有一点是,当你一直等待INTERVAL
时,会造成时间上的累积延迟。假设您的时间间隔为 50 毫秒。当您的 CPU 有太多工作要做或 accessData 函数花费太多时间时,您将无法在 50 毫秒内准确运行下一次迭代。假设它将是 52 毫秒,这是 2 毫秒的延迟。这些延迟会随着时间累积并影响您的精确度。
相反,你可以这样做:
time_point waitUntil = steady_clock::now() + initialWaitTime;
while(m_keepRunning){
if(steady_clock::now() >= waitUntil)
{
// ... do your work
waitUntil = waitUntil + chro::milliseconds(INTERVAL)
}
}
对于定时等待部分,@Useless 再次正确。旋转会给你的核心带来沉重的负担。相反,您应该使用条件或 timed_mutex。但上面的建议仍然有效。不要使用 sleep_for
,而是使用 sleep_until
。
杀死线程不起作用。问题是,如果你确实杀死了一个线程,它可能处于一个应该作为原子操作执行的多步骤操作的中间,使你的程序处于无效状态。相反,通知另一个线程自杀,然后等待它死亡。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。