繁体   English   中英

用进程和2个线程在C中进行信号处理不起作用

[英]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 (与killsigqueue发送的“假”消息相反)被发送到执行无效内存访问的线程,而不是整个进程。 因此,您无法拥有专用的段故障处理程序线程。 如果要处理它,则必须在发生它的线程中处理它。 (看到shell print Segmentation fault的原因是,当SIGSEGV被阻塞在线程中并且发生Segmentation fault时,内核会执行默认的杀死进程的动作。实际上,它是每个POSIX的UB,但这是Linux处理的方式UB。)

但是请注意,您可以让SIGSEGV的信号处理程序通过专用线程触发操作。 这样做的一种丑陋方法是使用另一个信号,您可以通过sigqueue发送(连同参数一起)。 更干净的方法(至少在我看来)是使SIGSEGV处理程序使用sem_post ,它是异步信号安全的,可用于唤醒另一个正在等待信号量的线程。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM