11

当我们的 UNIX/C 程序需要紧急退出时,我们使用 exit (3) 函数并安装 atexit (3) 处理程序以进行紧急清理。这种方法运行良好,直到我们的应用程序被线程化,此时 atexit() 处理程序停止以可预测的方式工作。

我们通过试验了解到一个错误,线程可能已经在 atexit() 处理程序中死亡,并且它们的堆栈被释放。

我没有在使用 atexit() 的标准链接线程消失中找到引用:从 main() 返回后线程不再存在,但它是在调用 atexit() 之前还是之后?Linux、FreeBSD 和 Mac 上的实际做法是什么?

在多线程程序中是否有一个很好的紧急清理模式?

4

1 回答 1

5

Posix 标准

Posix 似乎没有定义atexit处理程序是在线程终止之前还是之后调用的exit

进程“正常”终止有两种(或三种)方式。

  • 所有线程终止。当最后一个线程通过返回或调用退出时,pthread_exitatexit运行处理程序。在这种情况下,没有其他线程。(这取决于平台。如果主线程不是 by 终止,则某些平台可能会终止其他线程,而exit其他平台则不会)。

  • 一个线程调用exit. 在这种情况下,atexit将运行处理程序并终止所有线程。Posix 没有指定顺序。

  • main返回。这或多或少相当于调用exit()的最后一行main,因此可以按上述处理。

操作系统实践

在 Linux 中,文档https://linux.die.net/man/2/exit 说线程通过_exit调用终止exit_group,并且_exitatexit处理程序之后调用。因此,在 Linux 中,调用exit任何atexit处理程序时都会在线程终止之前运行。请注意,它们是在调用的线程上运行的exit,而不是在调用的线程上运行的atexit

如果您关心的话,在 Windows 上的行为是相同的。

紧急清理模式。

最好的模式是:永远不要处于需要紧急清理的状态。

  • 无法保证您的清理工作会运行,因为您可能会遇到kill -9停电或停电的情况。
  • 因此,您需要能够在这种情况下恢复。
  • 如果您可以从中恢复,您也可以从 恢复abort,因此您可以abort用于紧急出口。

如果您不能这样做,或者如果您想要进行“非常好的”清理,那么atexit处理程序应该没问题,前提是您首先优雅地停止进程中的所有线程,以防止在进行清理时进入不一致的状态。

于 2016-10-05T10:42:57.870 回答