c - 辅助线程中的信号处理

标签 c linux macos signals

我正在编写一个程序来演示辅助线程中的信号处理。在我的程序中,主线程生成 10 个线程,每个线程调用 sigwait 来等待信号。但就我而言,处理信号的是主线程。代码如下:

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <sys/types.h>
#include <errno.h>

volatile sig_atomic_t cont = 1;

volatile sig_atomic_t wsig = 0;
volatile sig_atomic_t wtid = 0;

int GetCurrentThreadId()
{
    return syscall(__NR_gettid);
}

void Segv1(int, siginfo_t *, void *)
{
    //printf("SIGSEGV signal on illegal memory access handled by thread: %d\n", GetCurrentThreadId());
    wtid = GetCurrentThreadId();
    wsig = SIGSEGV;
    _exit(SIGSEGV);
}

void Fpe1(int , siginfo_t *, void *)
{
    wtid = GetCurrentThreadId();
    wsig = SIGFPE;
    _exit(SIGFPE);
}

void User1(int, siginfo_t *, void *)
{
    wtid = GetCurrentThreadId();
    wsig = SIGUSR1;
}


void* ThreadFunc (void*)
{
    sigset_t sigs;
    sigemptyset(&sigs);
    sigaddset(&sigs, SIGUSR1);
    sigaddset(&sigs, SIGSEGV);
    sigaddset(&sigs, SIGFPE);
    pthread_sigmask(SIG_BLOCK, &sigs, NULL);
    //printf("Thread: %d starts\n", GetCurrentThreadId());
    while(cont) {
        //printf("Thread: %d enters into loop\n", GetCurrentThreadId());
        //int s = sigwaitinfo(&sigs, NULL);
        //int sig;
        //int s = sigwait(&sigs, &sig);
        //printf("A signal\n");
        /*if(s==0) {
            sigaddset(&sigs, sig);
            printf("Signal %d handled from thread: %d\n", sig, GetCurrentThreadId());
            if(sig==SIGFPE||sig==SIGSEGV)
                return NULL;
        } else {
            printf("sigwaitinfo failed with %d\n", s);
            break;
        }*/
        int s = sigsuspend(&sigs);
        switch(wsig) {
            case SIGSEGV:
                printf("Segmenation fault in thread: %d Current thread id: %d\n", wtid, GetCurrentThreadId());
                exit(1);
                break;
            case SIGFPE:
                printf("Floating point exception in thread: %d Current thread id: %d\n", wtid, GetCurrentThreadId());
                exit(1);
                break;
            case SIGUSR1:
                printf("User 1 signal in thread: %d Current thread id: %d\n", wtid, GetCurrentThreadId());
                break;
            default:
                printf("Unhandled signal: %d in thread: %d Current thread id: %d\n", wsig, wtid, GetCurrentThreadId());
                break;
        }
    }

    printf("Thread: %d ends\n", GetCurrentThreadId());

    return NULL;
}

int main()
{
    printf("My PID: %d\n", getpid());
    printf("SIGSEGV: %d\nSIGFPE: %d\nSIGUSR1: %d\n", SIGSEGV, SIGFPE, SIGUSR1);
    //Create a thread for signal
    struct sigaction act;
    memset(&act, 0, sizeof act);
    act.sa_sigaction = User1;
    act.sa_flags    = SA_SIGINFO;

    //Set Handler for SIGUSR1 signal.
    if(sigaction(SIGUSR1, &act, NULL)<0) {
        fprintf(stderr, "sigaction failed\n");
        return 1;
    }

    //Set handler for SIGSEGV signal.
    act.sa_sigaction    = Segv1;
    sigaction(SIGSEGV, &act, NULL);

    //Set handler for SIGFPE (floating point exception) signal.
    act.sa_sigaction    = Fpe1;
    sigaction(SIGFPE, &act, NULL);

    sigset_t sset;
    sigemptyset(&sset);
    sigaddset(&sset, SIGUSR1);
    sigaddset(&sset, SIGSEGV);
    sigaddset(&sset, SIGFPE);
    //pthread_sigmask(SIG_BLOCK, &sset, NULL);
    const int numthreads = 10;
    pthread_t tid[numthreads];
    for(int i=0;i<numthreads;++i)
        pthread_create(&tid[i], NULL, ThreadFunc, NULL);

    sleep(numthreads/2);

    int sleepval = 15;
    int pid = fork();
    if(pid) {
        while(sleepval) {
            sleepval = sleep(sleepval);
            //It might get interrupted with signal.
            switch(wsig) {
                case SIGSEGV:
                    printf("Segmenation fault in thread: %d\n", wtid);
                    exit(1);
                    break;
                case SIGFPE:
                    printf("Floating point exception in thread: %d\n", wtid);
                    exit(1);
                    break;
                case SIGUSR1:
                    printf("User 1 signal in thread: %d\n", wtid);
                    break;
                default:
                    printf("Unhandled signal: %d in thread: %d\n", wsig, wtid);
                    break;
            }
        }

    } else {
        for(int i=0;i<10;++i) {
            kill(getppid(), SIGUSR1);
            //If sleep is not used, signal SIGUSR1 will be handled one time in parent
            //as other signals will be ignored while SIGUSR1 is being handled.
            sleep(1);
        }
        return 0;
    }

    int * a = 0;
    //*a = 1;
    int c=0;
    //c = 0;
    int b = 1/c; //send SIGFPE signal.
    return 0;
}

在Linux和Mac OS X上有没有拾取线程处理信号的规则?我应该怎么做才能在辅助线程中处理信号?

在上面的程序中,我无法在辅助线程中处理信号。有什么问题吗?

最佳答案

我建议您应该在主线程中 SIG_BLOCK 需要的信号(现在已注释掉)并在其他线程中 SIG_UNBLOCK 它们(现在 SIG_BLOCK)。或者你可以生成你的线程,然后在主线程中生成 SIG_BLOCK,因为生成的线程从父线程获得它们的 sigmask。 而且sigsuspend的参数不是你要唤醒的信号,反之亦然。

关于c - 辅助线程中的信号处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25659579/

相关文章:

可以语句 char str[] ="abcdef";和 char *str ="abcdef";用于解释C中的字符数组和字符串文字?

linux - 在 Bash 中将一个变量分配给另一个变量?

linux - 使用 pipe 而不是 pipe2 时,在 fork 之后阻止在管道上读取

java - 在 Runtime.getRuntime().exec() 中出现错误 :/bin/bash: No such file or directory

python - Python 中的 SSL 模块不可用(在 OSX 上)

linux - 无法在 Mac OS X El Capitan 上编译 CUDA + OpenGL 程序

c - 枚举当前加载的所有共享对象的所有 ELF 部分

c - 如何在 C 中循环 char 指针?

linux - dmesg 没有记录任何内容

c - 字符串创建时的段错误