【问题标题】:Signal handling in secondary thread辅助线程中的信号处理
【发布时间】:2014-10-28 20:31:01
【问题描述】:

我正在编写一个程序来演示辅助线程中的信号处理。在我的程序中,主线程产生 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 上选择线程进行信号处理是否有任何规则?我应该怎么做才能让信号在辅助线程中得到处理?

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

【问题讨论】:

  • 首先在上面的链接中得到了回答。但我面临第二部分的问题(在辅助线程中处理信号)。
  • 第二个也有答案。
  • 仍然,我无法解决第二部分。你能提到它的答案吗?

标签: c linux macos signals


【解决方案1】:

在 Linux 和 Mac OS X 上选择线程进行信号处理有什么规则吗?

有,见Signal Generation and Delivery

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 第二个选项可能有竞争条件。
    • 我没有看到任何竞争条件。你认为它可以在哪里?
    • 在信号处理线程开始后,在保证它们获得信号之前有一个窗口。这是否重要取决于您将要做什么。
    • 是的,同意,但是这种条件竞赛也应该是首选,不是吗?
    • @dbasic 我检查了。为我工作。你改变了什么?
    猜你喜欢
    • 2016-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-25
    • 1970-01-01
    • 2015-08-23
    • 2014-03-27
    • 1970-01-01
    相关资源
    最近更新 更多