微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C++ 在析构函数中杀死一个线程

如何解决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 举报,一经查实,本站将立刻删除。