【问题标题】:How to properly terminate a thread in a signal handler?如何正确终止信号处理程序中的线程?
【发布时间】:2014-11-15 00:49:35
【问题描述】:

我想为 SIGSEGV、SIGILL 和可能的其他一些信号设置一个信号处理程序,而不是终止整个进程,而是终止有问题的线程,并可能在某处设置一个标志,以便监控线程可以抱怨并启动另一个线程。我不确定是否有安全的方法来做到这一点。 Pthreads 似乎提供了退出当前线程以及取消另一个线程的功能,但这些可能会调用一堆退出处理程序。即使他们不这样做,似乎在许多情况下它们不是异步信号安全的,尽管这些情况是可以避免的。有没有我可以调用的低级函数来破坏线程?假设我以异步信号安全的方式修改我自己的数据结构,并且没有获取互斥体,是否存在 pthread/其他全局数据结构可能仅因终止于 SIGSEGV 的线程而处于不一致状态?想到 malloc,但 malloc 本身不应该 SIGSEGV/SIGILL,除非 libc 有问题。我意识到 POSIX 在这里非常保守,并且不做任何保证。只要有办法在实践中做到这一点,我就很高兴。顺便说一句,分叉不是一种选择。

【问题讨论】:

  • 使用单独的进程。一个进程中的所有线程都可以访问相同的内存空间,因此它们都可能在达到导致段错误的点之前弄乱内部数据结构(例如 malloc 和 co)。使用进程而不是线程将为您提供适当的分离。
  • malloc 绝对不会在SIGSEGV 中出现malloc 中的错误,如果你破坏了它的数据结构的话。这是你的程序的错。

标签: c linux multithreading signals posix


【解决方案1】:

如果SIGSEGV/SIGILL/等。 发生在您自己的代码中,信号处理程序将不会在异步信号上下文中运行(它基本上是一个同步信号,但如果它发生在标准库函数中,它仍然是一个 AS 上下文),所以您可以从信号处理程序合法地调用pthread_exit。但是,仍然存在使这种做法令人怀疑的问题:

  • SIGSEGV/SIGILL/等。除非您通过raisekillpthread_killsigqueue 等方式生成行为已定义的程序,否则绝不会出现在这些程序中(在某些特殊情况下,它们 异步信号)。否则,它们表示程序具有未定义的行为。如果程序调用了未定义的行为,则所有赌注都关闭。 UB 不是孤立于特定线程或特定时间序列的。如果程序有 UB,它的整个输出/行为是没有意义的。

  • 1234563标准库(例如在malloc 中)而不是在您的代码中。在这种情况下,信号处理程序在 AS 安全上下文中运行,并且不能调用 pthread_exit。当然程序已经有了 UB(见上一点),但即使你想假装这不是问题,你仍然有麻烦。

如果您的程序遇到此类崩溃,您需要找到原因并修复它,而不是尝试使用信号处理程序修补它。 Valgrind 是你的朋友。如果这不可能,您最好的办法是将崩溃代码隔离到单独的进程中,您可以在其中推断如果它们异步崩溃会发生什么,而不是将崩溃代码放在同一进程中(关于代码行为的任何进一步推理都是无效的一旦你知道它会崩溃)。

【讨论】:

  • 完美回答了我的问题。这实际上是针对一个编译东西、dlopen 的东西,然后运行代码的系统——用 C 语言实时编码。所以错误是不可避免的,这个想法只是做最少的坏事。看起来,因为程序可能基本上对随机内存位置做任何事情,所以没有办法保证有故障的线程不会导致其余的线程瘫痪。但至少这里更有可能的结果是,好的线程保持良好,并且可以在不停止程序的情况下修复和重新编译代码。
  • 对于这种用例,您确实应该在单独的进程中运行代码。使用这种方法可能取得任何成功的唯一方法是,当您运行的代码从主程序访问很少或没有共享数据时(即便如此,缓冲区溢出可能会破坏主程序中的数据) , 但是这样的用例正是那些很容易转移到单独进程中的用例。难以转移到单独进程的情况是具有大量共享的情况,并且是那些有缺陷的模块会破坏整个程序状态的情况。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-26
  • 2012-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多