在多线程环境中捕获信号

cam*_*ccc 6 c multithreading signals longjmp

我有一个大型程序,需要尽可能具有弹性,并具有大量的线程.我需要捕获所有信号SIGBUS SIGSEGV,并在必要时重新初始化问题线程,或禁用线程继续减少功能.

我的第一个想法是做一个setjump,然后设置信号处理程序,可以记录问题,然后longjump回到线程中的恢复点.有一个问题是信号处理程序需要确定信号来自哪个线程,使用适当的跳转缓冲区作为跳回到错误的线程将是无用的.

有没有人知道如何确定信号处理程序中的违规线程?

456*_*976 2

在我的 Linux 机器上使用syscall(SYS_gettid)对我有用:gcc pt.c -lpthread -Wall -Wextra

//pt.c
#define _GNU_SOURCE
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <setjmp.h>
#include <signal.h>
#include <string.h>
#include <ucontext.h>
#include <stdlib.h>

static sigjmp_buf jmpbuf[65536];

static void handler(int sig, siginfo_t *siginfo, void *context)
{
    //ucontext_t *ucontext = context;
    pid_t tid = syscall(SYS_gettid);

    printf("Thread %d in handler, signal %d\n", tid, sig);
    siglongjmp(jmpbuf[tid], 1);
}

static void *threadfunc(void *data)
{
    int index, segvindex = *(int *)data;
    pid_t tid = syscall(SYS_gettid);

    for(index = 0; index < 500; index++) {
        if (sigsetjmp(jmpbuf[tid], 1) == 1) {
            printf("Recovery of thread %d\n", tid); 
            continue;
        }
        printf("Thread %d, index %d\n", tid, index);
        if (index % 5 == segvindex) {
            printf("%zu\n", strlen((char *)2)); // SIGSEGV
        }
        pthread_yield();
    }
    return NULL;
}

int main(void)
{
    pthread_t thread1, thread2, thread3;
    int segvindex1 = rand() % 5;
    int segvindex2 = rand() % 5;
    int segvindex3 = rand() % 5;
    struct sigaction sact;

    memset(&sact, 0, sizeof sact);
    sact.sa_sigaction = handler;
    sact.sa_flags = SA_SIGINFO;
    if (sigaction(SIGSEGV, &sact, NULL) < 0) {
        perror("sigaction");
        return 1;
    }
    pthread_create(&thread1, NULL, &threadfunc, (void *) &segvindex1);
    pthread_create(&thread2, NULL, &threadfunc, (void *) &segvindex2);
    pthread_create(&thread3, NULL, &threadfunc, (void *) &segvindex3);
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    pthread_join(thread3, NULL);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

为了更加便携pthread_self可以使用。它是异步信号安全的。

但是获得 a 的线程SIGSEGV应该通过异步信号安全的方式启动一个新线程,并且不应该执行 a ,siglongjmp因为它可能导致调用非异步信号安全函数。