如何终止或停止 C++ 中的分离线程?

Posted

技术标签:

【中文标题】如何终止或停止 C++ 中的分离线程?【英文标题】:How to terminate or stop a detached thread in c++? 【发布时间】:2014-09-04 00:44:41 【问题描述】:

我有兴趣在 C++ 中终止/停止/杀死一个分离的线程。如何做到这一点?

void myThread()

    int loop = 0;
    while(true)
    
        std::this_thread::sleep_for(std::chrono::seconds(5));
        ++loop;
    


void testThread()

    std::thread globalThread(myThread);
    globalThread.detach();


int main(void)

    testThread();
    for(unsigned int i=0; i < 1000; i++)
    
        cout << "i = " << i << endl;
    
    return 0;

我想“停止”/“终止” globalThread() 的原因是因为 valgrind 列出了这是一种“可能丢失”的内存泄漏类型(152 字节)。处理这个问题的最佳方法是什么?

【问题讨论】:

相关/重复:***.com/q/12207684 重申在这个问题和其他地方所说的话,你现在正在做的事情,甚至你似乎想要做的事情,都是不安全的。返回的主线程以非优雅的方式杀死globalThread,唯一“正确”的做事方式是让主线程通过mutex等发送请求,以打破其循环,并拥有主线程join 等待优雅终止确认。 看看这个 - [我的解决方案][1]。我已经回答了类似的问题。 [1]:***.com/a/32338982/5163650 如果是 Windows,请尝试 TerminateThread()。看起来它可能是基于这些函数调用的 Windows。 【参考方案1】:

没有规定停止另一个线程;无论是分离的还是可连接的。

停止线程的唯一方法是让线程从初始线程函数返回。

在这种特殊情况下,我建议进行以下更改:

    不要分离线程。在 main() 中实例化它。 添加一个布尔值和一个std::mutex,布尔值被初始化为false 每次通过线程的内部循环,使用std::unique_lock 锁定互斥锁,取布尔值,然后解锁互斥锁。解锁互斥锁后,如果布尔值为true,则跳出循环并返回。 在main()中,退出前:锁定互斥体,设置bool标志为true,解锁互斥体,然后加入线程

这并不完美,因为第二个线程最多需要五秒钟来检查 bool 标志并返回。但是,这将是第一步。

【讨论】:

我认为 mutex 对于一个简单的标志来说太过分了。在我看来,这更像是 atomic&lt;bool&gt;atomic_flag 的工作。 @dyp 我同意,但即使这样也不能保证线程在main() 退出之前终止。 @avakar 你加入了一个 detached 线程......怎么样? OP已经建立线程分离;没有什么可以加入的。 @WhozCraig,我会通过注意第 1 步“不要分离线程”来加入它。 @avakar 同样。我也会的。如前所述,对OP问题的简短回答是,您根本做不到。 (不幸的是,标题问题与结束正文问题不同)。【参考方案2】:

您可以低于 C++ 标准并使用特定于操作系统的功能,例如在设置信号掩码的同时向您自己的进程发送信号,以便仅将其传递给分离的线程 - 处理程序可以设置从您的线程轮询的标志.如果您的主程序等待的时间超过轮询周期加上一点,您可以猜测它应该已经终止;-P。相同的一般思想可以用于任何其他信号机制,例如 atomic terminate-asap 标志变量。

或者,并且仅作为最后的手段,有pthread_cancel 和类似的。请注意,像这样的异步取消通常是一件众所周知的危险事情 - 您应该注意您终止的线程不能在任何具有锁定/占用资源的代码中,否则您可能会出现死锁、泄漏和/或未定义的行为.例如,您的代码调用std::this_thread::sleep_for(std::chrono::seconds(5)); - 如果在间隔到期时要求操作系统进行回调,但之后继续执行的函数使用终止线程的堆栈怎么办?一个安全的例子是,如果线程在您的应用程序中循环执行一些简单的数字运算。

否则,如果您首先避免分离线程,Sam 的答案会记录一个替代方案....

【讨论】:

【参考方案3】:

没有办法彻底关闭分离的线程。这样做需要等待清理完成,并且只有在线程可连接时才能这样做。

例如,假设线程持有另一个线程需要获取的互斥锁才能彻底关闭。彻底关闭该线程的唯一方法是诱导它释放该互斥体。这需要线程的合作。

考虑线程是否打开了一个文件并持有该文件的锁。中止线程将使文件保持锁定状态,直到进程完成。

考虑线程是否拥有保护某些共享状态的互斥锁,并且已将该共享状态暂时置于不一致状态。如果您终止线程,则互斥锁将永远不会被释放,或者互斥锁将在受保护的数据处于不一致状态时被释放。这可能会导致崩溃。

你需要一个线程的合作才能彻底关闭它。

【讨论】:

这是误导。你再次概括了所有地方的所有代码。请停止这样做。有些线程不需要清理,例如,在某些情况下,您有 2 个或多个线程竞相寻找解决方案,并且在找到解决方案之前没有写入或传输任何数据,当这种情况发生时,完全可以接受获胜线程的解决方案,杀死尚未找到解决方案的线程,而不用担心数据损坏。 IPC,信号处理?一切都在你的陈述中被掩盖了。 @Owl 我说没有办法干净地关闭一个分离的线程。你举了一个例子,你干净地关闭了一个分离的线程。你在反对我没有说的话。 1) 在不等待加入的情况下,您看不到任何“清理”线程的方法。我实际上认为这是错误的。 2)我的观点是有些线程不需要清理,这与你认为我所说的不太一样。 我说没有办法干净地关闭一个分离的线程并解释了原因。这回答了OP提出的问题。没有理由认为 OP 认为始终干净地关闭所有线程是必不可少的,我从未说过或暗示它是,只是回答了他的问题。 @Owl“如果你给一个宽限期,你知道线程已经终止”?!请告诉我宽限期需要多长时间以及您在哪里找到这种智慧。【参考方案4】:

注意到“否”的直接答案没有多大帮助:

通常你会看到类似于“使用你自己的线程间通信”的答案

这是在主线程和子线程之间共享的原子布尔值,还是通过 OS 方法向另一个线程发送信号。

将焦点转移到您希望分离线程何时终止的具体细节上,而不是“谁在杀人”可能会有所帮助。

https://en.cppreference.com/w/cpp/thread/notify_all_at_thread_exit

查看像上面这样的代码示例帮助我解决了我正在处理的问题(主线程模糊地死去,孩子们出现了段错误),我希望它对你有所帮助。

【讨论】:

以上是关于如何终止或停止 C++ 中的分离线程?的主要内容,如果未能解决你的问题,请参考以下文章

无法永远分离线程c ++

Qt中如何设置按钮点击终止线程

C++ 分离的线程可以通过哪些可能的方式发出它正在终止的信号?

如何正确停止线程

C++ 在 Windows API 中创建一个单独的线程,程序终止?

如何安全地终止线程? (使用指针)C++