std::thread 线程在对象中分离,它何时终止?
Posted
技术标签:
【中文标题】std::thread 线程在对象中分离,它何时终止?【英文标题】:std::thread thread spun off in object, when does it terminate? 【发布时间】:2016-10-19 17:43:59 【问题描述】:如果我在Bar
的构造函数中拆分std::thread
,它什么时候停止运行?当Bar
实例被破坏时,它是否保证停止?
class Bar
public:
Bar() : thread(&Bar:foo, this)
...
void foo()
while (true) //do stuff//
private:
std::thread thread;
;
编辑:如何正确终止析构函数中的std::thread
?
【问题讨论】:
见***.com/a/13984169/12711 @kfsone 感谢您的评论。您能否详细说明一下哪个未定义的行为线程(&Bar::foo, this)依赖于 @user695652,在构造函数的初始化列表中传递this
(或对象成员)通常很危险。您的对象仅包含线程,因此在此示例中没有任何危害,但如果它有更多字段,您应该注意您的线程可能在对象完全构造之前开始执行。
【参考方案1】:
如果我在 Bar 的构造函数中剥离一个 std::thread 什么时候做 停止运行?
只要线程执行您提供的可调用对象,线程就会运行,或者程序终止。
Bar 实例被破坏时是否保证停止?
没有。为了保证这一点,在Bar
析构函数中调用std::thread::join
。
实际上,如果您在Bar::~Bar
之前没有调用thread::join
或thread::detach
,那么您的应用程序将通过自动调用std::terminate
来终止。所以您必须致电join
(首选)或detach
(不太推荐)。
您还想在对象析构函数上调用therad::join
,因为如果在您的线程正在处理该对象时对象被破坏,则生成的线程依赖于对象是活动的 - 您是使用破坏的对象,您的代码中将有未定义的行为。
【讨论】:
感谢您的回答。我不明白最后一部分“如果你没有调用 thread::join 或 thread::detach”,那么在我上面的例子中,线程会发生什么? 如果你不调用thread::join
或thread::detach
并且线程的析构函数开始运行——整个应用程序终止。
嗯,有点。 “崩溃”是操作系统实际杀死您的进程的时间。在这里,程序本身退出。当然,标准并没有真正定义术语“崩溃”
我明白了,虽然我仍然不明白如何在析构函数中正确终止我的线程,但由于我的线程在无限循环中运行,yield 不会起作用。
@user695652:从线程外部终止线程是危险的(例如,另一个线程通常不容易或不可能知道线程是否持有互斥锁),因此被广泛接受的方式终止线程是以某种方式发出信号退出。您的线程的工作循环可能类似于while (!exit_thread) ...
而不是while (true) ...
。 exit_thread
将是一些对象或函数,可用于告诉线程(以线程安全的方式)它应该清理并退出。【参考方案2】:
简短回答:是和否。是的,线程结束,但不是通过通常的方式(杀死线程),而是通过主线程由于std::terminate
调用而退出。
长答案:只有在底层函数 (thread) 执行完毕后才能安全地销毁线程。这可以通过两种方式完成
调用join()
,等待线程完成(在你的情况下,永远不会)
调用detach()
,将线程与主线程分离(在这种情况下,线程将在主线程关闭时结束 - 当程序终止时)。
如果在所有those conditions 都不适用的情况下调用析构函数,则调用std::terminate
:
它是默认构造的
它被移出
join()
已被调用
detach()
已被调用
【讨论】:
【参考方案3】:C++ 线程工具不包含用于终止线程的内置机制。相反,您必须自己决定:a)一种机制来通知线程它应该终止,b)当进程终止并且操作系统只是停止运行它的线程时,您不关心线程在操作中被中止更多。
std::thread
对象不是线程本身,而是一个包含线程描述符/句柄的不透明对象,因此理论上它可以在不影响线程的情况下被销毁,并且有支持和反对自动终止线程的论据本身。相反,作为一种折衷方案,它是为了在线程保持运行和连接状态时销毁 std::thread
对象会导致应用程序终止。
因此,在它的析构函数中有这样的代码:
~thread()
if (this->joinable())
std::terminate(...);
这是一个使用简单原子变量并在线程中检查它的示例。对于更复杂的情况,您可能需要考虑使用condition_variable
或其他更复杂的信号机制。
#include <thread>
#include <atomic>
#include <chrono>
#include <iostream>
class S
std::atomic<bool> running_;
std::thread thread_;
public:
S() : running_(true), thread_([this] () work(); )
void cancel() running_ = false;
~S()
if ( running_ )
cancel();
if ( thread_.joinable() )
thread_.join();
private:
void work()
while ( running_ )
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::cout << "tick ...\n";
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::cout << "... tock\n";
std::cout << "!running\n";
;
int main()
std::cout << "main()\n";
S s;
std::this_thread::sleep_for(std::chrono::milliseconds(2750));
std::cout << "end of main, should see a tock and then end\n";
std::cout << "finished\n";
现场演示:http://coliru.stacked-crooked.com/a/3b179f0f9f8bc2e1
【讨论】:
以上是关于std::thread 线程在对象中分离,它何时终止?的主要内容,如果未能解决你的问题,请参考以下文章
何时在 tableView 单元中分离 firebase 侦听器?