辅助线程中的信号处理

时间:2014-09-04 07:24:45

标签: c linux macos signals

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

#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上是否有任何获取信号处理线程的规则?我该怎么做才能在二级线程中处理信号?

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

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:2)

  

在Linux和Mac OS X上是否有任何获取信号处理线程的规则?

有,见Signal Generation and Delivery

  

在信号生成和传送或接受之间的时间内,信号被称为待决。通常,应用程序无法检测到此间隔。但是,信号可以阻止从传递到线程。如果与阻塞信号相关联的动作不是忽略该信号,并且如果为该线程生成该信号,则该信号将保持未决状态直到它被解除阻塞,当它被选中并通过调用返回时它被接受。 sigwait()函数或与之关联的操作设置为忽略该信号。 为进程生成的信号应该传递给进程内的其中一个线程,这些线程在调用sigwait()函数时选择该信号或​​者没有阻止信号传递。如果有在调用sigwait()函数时没有线程选择该信号,并且如果进程中的所有线程都阻塞了信号的传递,则该信号将在进程中保持挂起状态,直到线程调用sigwait()函数选择该信号为止,线程解除阻塞信号的传递,或者将与信号相关联的动作设置为忽略该信号。如果与阻塞信号相关联的操作是忽略该信号,并且如果为该过程生成该信号,则未指定该信号在生成时是立即丢弃还是保持未决。