[英]Signal handling in C with process and 2 threads doesn't work
我正在使用以下示例(该示例基于linux中pthread_sigmask的手册页中的示例):
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
/* Simple error handling functions */
#define handle_error_en(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
static void * silly_worker(void *arg)
{
for(int index=0,max=5; index<max; ++index) {
printf("waiting %d of %d\n",index,max);
sleep(1);
}
puts("Finished waiting. Here comes the SIGSEGV");
strcpy(NULL,"this will crash");
}
static void *
sig_thread(void *arg)
{
sigset_t *set = (sigset_t *) arg;
int s, sig;
for (;;) {
s = sigwait(set, &sig);
if (s != 0)
handle_error_en(s, "sigwait");
printf("Signal handling thread got signal %d\n", sig);
}
}
int
main(int argc, char *argv[])
{
pthread_t thread;
pthread_t thread2;
sigset_t set;
int s;
/* Block SIGINT; other threads created by main() will inherit
a copy of the signal mask. */
sigemptyset(&set);
sigaddset(&set, SIGQUIT);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGSEGV);
s = pthread_sigmask(SIG_BLOCK, &set, NULL);
if (s != 0)
handle_error_en(s, "pthread_sigmask");
s = pthread_create(&thread, NULL, &sig_thread, (void *) &set);
if (s != 0)
handle_error_en(s, "pthread_create");
/* Main thread carries on to create other threads and/or do
other work */
s = pthread_create(&thread2, NULL, &silly_worker, (void *) &set);
if (s != 0)
handle_error_en(s, "pthread_create");
pause(); /* Dummy pause so we can test program */
}
根据手册页,这应该捕获由silly_worker线程生成的SIGSEGV。 但事实并非如此。 实际上,我不确定是什么机构正在发出信号。 当程序运行时,我得到以下输出:
waiting 0 of 5
waiting 1 of 5
waiting 2 of 5
waiting 3 of 5
waiting 4 of 5
Finished waiting. Here comes the SIGSEGV
Segmentation fault
您会看到信号处理程序没有输出“ Segmentation fault”字符串,因此它必须来自默认处理程序。 如果是默认值,则可能会破坏示例的目的-设置信号处理程序并捕获信号并对它们执行某些操作。
我可以找到很多处理程序的示例,但是没有一个适用于这种情况:它们都没有演示导致真正明显的SIGSEGV的线程,并在其自定义处理程序中捕获并报告了错误。
问题仍然存在:如何获取自定义信号处理程序以从该SIGSEGV线程获取信号?
来自无效内存访问的SIGSEGV
(与kill
或sigqueue
发送的“假”消息相反)被发送到执行无效内存访问的线程,而不是整个进程。 因此,您无法拥有专用的段故障处理程序线程。 如果要处理它,则必须在发生它的线程中处理它。 (看到shell print Segmentation fault
的原因是,当SIGSEGV
被阻塞在线程中并且发生Segmentation fault
时,内核会执行默认的杀死进程的动作。实际上,它是每个POSIX的UB,但这是Linux处理的方式UB。)
但是请注意,您可以让SIGSEGV
的信号处理程序通过专用线程触发操作。 这样做的一种丑陋方法是使用另一个信号,您可以通过sigqueue
发送(连同参数一起)。 更干净的方法(至少在我看来)是使SIGSEGV
处理程序使用sem_post
,它是异步信号安全的,可用于唤醒另一个正在等待信号量的线程。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.