这是一个元问题,因为我认为我有一个适合我的解决方案,但它也有其缺点和缺点。我需要做一个相当普通的事情,在一个线程上捕获SIGSEGV
(没有专用的崩溃处理线程),转储一些调试信息并退出。
这里要了解的事实是,崩溃时,我的应用程序运行llvm-symbolizer
会花一些时间(相对而言)并导致产生结果(由于clone + execve
或超出线程的时间量),我已经看到后者在自己进行符号化时发生使用libLLVM
进行处理)。进行所有这些操作的原因是获得具有脱字符符号和行/文件信息(存储在单独的DWP文件中)的堆栈跟踪。出于明显的原因,我不希望在SIGSEGV
处理程序上发生任何事情,因为我打算在应用程序(线程组)执行后终止它,并且永远不要从信号处理程序中返回。
尽管我不了解Linux信号处理以及glibc的包装器对它们的处理能力,但我并不了解基本的陷阱,但是关于信号处理的具体细节并没有太多信息,例如同步信号处理程序是否获得任何特殊的优先级在调度方面。
集思广益,我有一些想法和缺点:
pthread_kill(<every other thread>, SIGSTOP)
-具有更多线程的笨拙功能,可与信号处理程序进行交互,这似乎可能具有意外的副作用。还需要拦截其他库中的线程创建,以跟踪线程列表,并在每次系统调用时增加抢占的机会。一旦它们停下来指向syscall exit
stub 或完全使用SIGKILL
,甚至可能更改其上下文。 pthread_cancel/pthread_testcancel
)。更安全,但需要大量维护,并且在整个代码库中,除了会产生轻微的性能开销外,还有些麻烦。全局标志还可能导致错误级联,因为该程序已经处于不可预测的状态,因此让任何其他线程在那里运行已经不是很大。 FIFO
调度策略并提高优先级,因此成为该组中唯一可运行的线程。 环境是具有
glibc
的典型的基于NPTL
的Linux(4.4)发行版。我知道崩溃处理程序现在相当普遍,因此我相信我选择的方法都不是那么好,尤其是考虑到我从未见过调度程序“hack”曾经被这种方式使用过。因此,有没有人比调度程序“hack”更好,更清洁,风险更低的替代品,我是否在我对信号的一般想法中遗漏了任何要点?
编辑:似乎我并没有真正考虑过MP(根据注释),也没有在MP情况下其他线程仍可运行并且可以愉快地继续在其他处理器上与
FIFO
线程一起运行的事实。但是,我可以将进程的亲和力更改为仅在与崩溃线程相同的内核上执行,这基本上将在时间表边界有效冻结所有其他线程。但是,这仍然保留了“由于阻塞IO而导致的FIFO线程屈服”的情况。似乎
FIFO + SIGSTOP
选项是最好的选择,尽管我确实想知道是否还有其他技巧可以使线程无法使用SIGSTOP
来安排。从文档上看,似乎不可能将线程的CPU亲和力设置为零(将其置于技术上可运行的边缘状态,除非没有可用的处理器可运行)。
最佳答案
upon crash, my application runs llvm-symbolizer
这很可能导致死锁。我找不到关于llvm-symbolizer是异步信号安全的任何声明。很可能会调用
malloc
,如果这样的话,如果崩溃也发生在malloc
内部(例如,由于其他地方的堆损坏),则肯定会死锁。Switching to FIFO scheduling policy and raising priority therefore becoming the only runnable thread in that group.
我相信您错了:只要
SCHED_FIFO
线程是可运行的,它将一直运行(即不会发出任何阻塞的系统调用)。如果该线程确实发出了这样的调用(必须这样做:例如,用单独的open
文件.dwp
),它将阻塞并且其他线程将变为可运行状态。TL; DR:没有简单的方法可以实现您想要的目标,而且无论如何似乎都是不必要的:您在乎什么,当崩溃的线程完成其业务时,其他线程继续运行?
关于linux - 如何确保信号处理程序永远不会屈服于同一进程组中的线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49958057/