使用全局std::atomic<int>变量作为标志。主函数线程:使用1初始化标志工作线程:判断原子标志,并在无限循环中做一些工作Main函数将标志设置为0,并在一些睡眠后调用exit()。所有线程都将终止。调用exit后,std::atomic是否持续超过线程生命期是无法保证的。假设std::atomic在线程终止前处于描述状态,则线程仍在访问它。什么行为?从测试来看是可以的,但我不太确定。有没有什么标准的参照物?
std::atomic<int>
0
exit()
std::atomic
ckx4rj1h1#
干净的程序终止是一个难题。如果在main返回(或从末尾福尔斯)或调用exit时有一个活动线程,则很难避免未定义行为。在C的UB中,在它所引用的对象被销毁后访问任何变量,即使该销毁是微不足道的。有时候你可以访问变量在销毁后使用的 storage,但这是一个非常不同的事情,甚至看起来也非常不同(可能有一些相对较新的C20特性涉及原始类型,但这种情况不包括atomic s,所以在这里不适用)。处理这类问题的正确方法是将工作线程中的工作量限制在程序终止检查之间。这又需要大量的程序员开销。睡眠通常是你的设计有严重问题的迹象。你的代码应该总是在等待一个信号,或者在它的任务上取得进展。如果您无法清理环境,那么std::abort可能是更合适的关闭机制,因为您没有正确地清理环境。假装你在使用std::exit不会让事情变得更好。但你应该首先尝试做一个正确的关机。正确的关闭尝试可能涉及一个信号量,计算有多少线程具有属性shutdown,一些线程在线程退出期货时做好准备以避免竞争条件,一些调用wait_for以确保您不会挂起错误。在您给予了所有事情足够的时间来解决并且事情还没有清理之后,您投降并abort,可能还记录了一条异常关闭消息。这避免了您的进程由于失控线程而无限期地挂起的机会,但是正确关闭的尝试意味着当事情没有出错时,您可以正确关闭并知道它发生了。调用exit时,您只是“希望”每个线程都已经完成,这与此相反。在这里,您可能正在执行一个异常的程序关闭 * 而不知道它 *。这意味着你不知道你有多频繁地冒UB的风险,不能记录你的程序异常关闭的频率,甚至不知道你的程序是否有可能以有序的方式关闭。相反,你“耸耸肩”,希望这不是一个问题。
main
exit
atomic
std::abort
std::exit
wait_for
abort
1条答案
按热度按时间ckx4rj1h1#
干净的程序终止是一个难题。
如果在
main
返回(或从末尾福尔斯)或调用exit
时有一个活动线程,则很难避免未定义行为。在C的UB中,在它所引用的对象被销毁后访问任何变量,即使该销毁是微不足道的。有时候你可以访问变量在销毁后使用的 storage,但这是一个非常不同的事情,甚至看起来也非常不同(可能有一些相对较新的C20特性涉及原始类型,但这种情况不包括
atomic
s,所以在这里不适用)。处理这类问题的正确方法是将工作线程中的工作量限制在程序终止检查之间。这又需要大量的程序员开销。
睡眠通常是你的设计有严重问题的迹象。你的代码应该总是在等待一个信号,或者在它的任务上取得进展。
如果您无法清理环境,那么
std::abort
可能是更合适的关闭机制,因为您没有正确地清理环境。假装你在使用std::exit
不会让事情变得更好。但你应该首先尝试做一个正确的关机。正确的关闭尝试可能涉及一个信号量,计算有多少线程具有属性shutdown,一些线程在线程退出期货时做好准备以避免竞争条件,一些调用
wait_for
以确保您不会挂起错误。在您给予了所有事情足够的时间来解决并且事情还没有清理之后,您投降并abort
,可能还记录了一条异常关闭消息。这避免了您的进程由于失控线程而无限期地挂起的机会,但是正确关闭的尝试意味着当事情没有出错时,您可以正确关闭并知道它发生了。
调用
exit
时,您只是“希望”每个线程都已经完成,这与此相反。在这里,您可能正在执行一个异常的程序关闭 * 而不知道它 *。这意味着你不知道你有多频繁地冒UB的风险,不能记录你的程序异常关闭的频率,甚至不知道你的程序是否有可能以有序的方式关闭。相反,你“耸耸肩”,希望这不是一个问题。