为什么pause(2)不会在辅助线程中返回?

时间:2016-02-02 05:43:27

标签: c multithreading signals interrupt pause

考虑我设置的这个例子来说明这一点。

#define _POSIX_C_SOURCE 199506L

#include <unistd.h>
#include <stdio.h>
#include <sys/time.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>

void hand(int sig);
void *thrfn(void *arg);

int main(void)
{
    struct sigaction act;
    struct itimerval timer;
    sigset_t mask;
    pthread_t thr;

    act.sa_handler = hand;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    sigaction(SIGALRM, &act, NULL);
    /* error checking omitted */

    timer.it_interval.tv_sec = 1;
    timer.it_interval.tv_usec = 500000;
    timer.it_value = timer.it_interval;
    /* ultimately I want to build a loop; hence repeating */
    setitimer(ITIMER_REAL, &timer, NULL);

    sigemptyset(&mask);
    pthread_sigmask(SIG_SETMASK, &mask, NULL);
    /* why doesn't this prevent SIGALRM from interrupting main? */
    pthread_create(&thr, NULL, thrfn, NULL);

    puts("Main thread done.");
    getchar();

    return 0;
}

void hand(int sig)
{
    (void)sig;
    write(STDOUT_FILENO, "Handler handled.\n", 17);
}

void *thrfn(void *arg)
{
    sigset_t mask;

    (void)arg;

    sigemptyset(&mask);
    sigaddset(&mask, SIGALRM);
    pthread_sigmask(SIG_SETMASK, &mask, NULL);
    /* why doesn't this make pause() return in this thread? */

    pause();
    puts("Off thread's pause returned.");
    pthread_exit(NULL);
}

这里是输出,用gcc编译:

Main thread done.
Handler handled.

消息之间大约有一秒半。

为什么我的第二个帖子pause永远不会回来?

1 个答案:

答案 0 :(得分:2)

我猜错误在pthread_sigmask的使用中。使用SIG_BLOCKSIG_UNBLOCK代替SIG_SETMASK,程序的行为与您期望的一样。

#define _POSIX_C_SOURCE 199506L

#include <unistd.h>
#include <stdio.h>
#include <sys/time.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>

void hand(int sig);
void *thrfn(void *arg);

int main(void)
{
    struct sigaction act;
    struct itimerval timer;
    sigset_t mask;
    pthread_t thr;

    act.sa_handler = hand;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    sigaction(SIGALRM, &act, NULL);
    /* error checking omitted */

    timer.it_interval.tv_sec = 1;
    timer.it_interval.tv_usec = 500000;
    timer.it_value = timer.it_interval;
    /* ultimately I want to build a loop; hence repeating */
    setitimer(ITIMER_REAL, &timer, NULL);

    sigemptyset(&mask);
    sigaddset(&mask, SIGALRM);
    pthread_sigmask(SIG_BLOCK, &mask, NULL);
    /* This prevent SIGALARM interrupring the main */
    pthread_create(&thr, NULL, thrfn, NULL);

    puts("Main thread done.");
    getchar();

    return 0;
}

void hand(int sig)
{
    (void)sig;
    write(STDOUT_FILENO, "Handler handled.\n", 17);
}

void *thrfn(void *arg)
{
    sigset_t mask;

    (void)arg;

    sigemptyset(&mask);
    sigaddset(&mask, SIGALRM);
    pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
    /* This make the pause() return on SIGALARM */
    pause();
    puts("Off thread's pause returned.");
    pthread_exit(NULL);
}

该程序提供以下输出:

$ ./test 
Main thread done.
Handler handled.
Off thread's pause returned.

您可能会找到答案herehere

特别是:

sigemptyset(&mask);
pthread_sigmask(SIG_SETMASK, &mask, NULL);

你正在取消主线程中的所有信号。同时,用:

sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
pthread_sigmask(SIG_SETMASK, &mask, NULL);

您只在子线程上阻止SIGALARM。这可能与你想做的事情相反。 请注意,使用SIG_SETMASK指定阻止信号集。