为了账号安全,请及时绑定邮箱和手机立即绑定

当main()退出时,分离线程会发生什么?

当main()退出时,分离线程会发生什么?

C++
猛跑小猪 2019-08-16 14:03:53
当main()退出时,分离线程会发生什么?假设我正在启动a std::thread然后detach()它,所以线程继续执行,即使std::thread它曾经代表它,超出范围。进一步假设程序没有用于加入分离的线程1的可靠协议,因此分离的线程在main()退出时仍然运行。我在标准中找不到任何东西(更确切地说,在N3797 C ++ 14草案中),它描述了应该发生的事情,1.10和30.3都没有包含相关的措辞。1另一个可能相当的问题是:“可以再次连接一个分离的线程”,因为无论你要发明什么协议加入,信号部分都必须在线程仍在运行时完成,并且OS调度程序可能决定在执行信令之后让线程休眠一小时,接收端无法可靠地检测到线程实际完成。如果运行main()脱离线程的运行是未定义的行为,那么任何使用std::thread::detach()都是未定义的行为,除非主线程永远不会退出2。因此,运行main()脱离线程的耗尽必须具有已定义的效果。问题是:在哪里(在C ++标准中,不是POSIX,而不是OS文档,......)是定义的那些效果。2分离的线程无法连接(在某种意义上std::thread::join())。您可以等待分离线程的结果(例如,通过未来std::packaged_task,或通过计数信号量或标志和条件变量),但这并不能保证线程已完成执行。事实上,除非你把信令部分进入线程的第一个自动对象的析构函数,也将在一般情况下,是运行的代码(析构函数)后的信号代码。如果操作系统安排主线程使用结果并在分离的线程完成运行所述析构函数之前退出,^ Wis定义会发生什么?
查看完整描述

3 回答

?
九州编程

TA贡献1785条经验 获得超4个赞

原始问题“ main()退出时分离线程会发生什么”的答案是:

它继续运行(因为标准并没有说它已停止),并且这是定义良好的,只要它既不接触其他线程的(自动| thread_local)变量也不接触静态对象。

这似乎允许允许线程管理器作为静态对象(注意[basic.start.term] / 4中的注释,因为指针的@dyp)。

当静态对象的破坏完成时会出现问题,因为执行进入只有信号处理程序允许的代码可以执行的状态([basic.start.term] / 1,第一句)。在C ++标准库中,只有<atomic>库([support.runtime] / 9,第二句)。特别是,通常 - 排除 condition_variable(它的实现定义是否保存在信号处理程序中使用,因为它不是其中的一部分<atomic>)。

除非你在这一点上解开堆栈,否则很难看出如何避免未定义的行为。

第二个问题的答案“可以再次加入分离的线程”是:

是的,与*_at_thread_exit系列函数(notify_all_at_thread_exit()std::promise::set_value_at_thread_exit(),...)。

如问题脚注[2]所述,发信号通知条件变量或信号量或原子计数器不足以加入分离的线程(在确保其执行结束发生之前 -在接收之前)通过等待线程表示信号),因为通常在例如notify_all()条件变量之后将执行更多代码,特别是自动和线程局部对象的析构函数。

运行信号作为线程的最后一件事(自动和线程局部对象的析构函数发生之后)是_at_thread_exit函数族的设计目的。

因此,为了避免在没有任何高于标准要求的实现保证的情况下未定义的行为,您需要(手动)使用_at_thread_exit执行信令的函数连接分离的线程,或者使分离的线程执行对于安全的代码信号处理程序也是。


查看完整回答
反对 回复 2019-08-16
?
慕田峪7331174

TA贡献1828条经验 获得超13个赞

程序退出后线程的命运是未定义的行为。但是现代操作系统会在关闭它时清理进程创建的所有线程。

在分离时std::thread,这三个条件将继续保持

  1. *this 不再拥有任何线程

  2. joinable()将始终等于false

  3. get_id()将等于std :: thread :: id()


查看完整回答
反对 回复 2019-08-16
  • 3 回答
  • 0 关注
  • 909 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信