使用3个线程进行信号处理时,谁是第4个线程

时间:2019-05-02 11:55:38

标签: c multithreading pthreads signals

我正在与线程一起使用,正在经历信号的反应。我知道printf系列功能不是信号安全功能,但为简单起见,我使用它。据说

  

当信号传递到已建立信号处理程序的多线程进程时,内核会任意选择一个   将信号传递到的过程中的线程   该线程中的处理程序。   传统的信号语义。这对于没有意义   多次执行信号处理动作的过程   对单个信号的响应。

要体验粗体文本,我编写了以下基本代码,但是当我按Ctrl-C时,得到的线程ID不同于创建的线程ID。这是谁?为什么我看不到其他线程可以捕获信号。

#include <pthread.h>
#include <stdio.h>
#include <signal.h>

pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cv = PTHREAD_COND_INITIALIZER;

int count = 0;
int globerr;

void *inc(void *arg) {
    fprintf(stderr, "Thread id = %d\n", (int)pthread_self());
    sleep(2);
    int error;
    for (int i = 0; i < 15; ++i) {
        if (error = pthread_mutex_lock(&mtx)) {
            globerr = error;
            return 0;
        }

        count++;
        printf("thread id = %d, count = %d\n", pthread_self(), count);
        if (count == 20) {

            printf("thread id = %d, SIGNAL count = %d\n", pthread_self(), count);
            pthread_cond_signal(&cv);
        }


        if (error = pthread_mutex_unlock(&mtx)) {
            globerr = error;
            return 0;
        }
    }
}

void* watcher(void *arg) {
    fprintf(stderr, "Thread id = %d\n", (int)pthread_self());
    sleep(2);
    int error;
    if (error = pthread_mutex_lock(&mtx)) {
        globerr = error;
        return 0;
    }

    while (count < 20) {
        printf("watcher thread id = %d, BLOCKING count = %d\n", pthread_self(), count);
        pthread_cond_wait(&cv, &mtx);
        printf("watcher thread id = %d, UNBLOCKING count = %d\n", pthread_self(), count);

    }


    printf("watcher thread id = %d, count = %d\n", pthread_self(), count);

    if (error = pthread_mutex_unlock(&mtx)) {
        globerr = error;
        return 0;
    }

}

static void signal_handler(int sig){
    if (sig == SIGINT)
        printf("Caught signal for Ctrl+C, Thread id = %d\n", (int)pthread_self());

    pthread_cancel(pthread_self());
}

int main(void) {
    struct sigaction sigact;
    sigact.sa_handler = signal_handler;
    sigemptyset(&sigact.sa_mask);
    sigact.sa_flags = 0;
    sigaction(SIGINT, &sigact, (struct sigaction *)NULL);

    pthread_t t[3];
    for (int i = 0; i < 2; ++i) {
        pthread_create(&t[i], 0, inc, 0);
    }

    pthread_create(&t[2], 0, watcher, 0);

    sleep(3);

    for (int i = 0; i < 3; ++i) {
        pthread_join(t[i], 0);
    }
}

示例输出

MacBook-Pro-2:cmake-build-debug soner$ ./client 
Thread id = 171921408
Thread id = 172457984
Thread id = 172994560
^CCaught signal for Ctrl+C, Thread id = 360719808
^CCaught signal for Ctrl+C, Thread id = 171921408
^CCaught signal for Ctrl+C, Thread id = 172457984
^CCaught signal for Ctrl+C, Thread id = 172994560

360719808是谁?

1 个答案:

答案 0 :(得分:1)

如果您多次调用pthread_create,则您的程序有四个线程:第四个是初始线程,该线程从程序开始就存在。您可以将其视为线程过程为main的线程。

在这样的程序中,您应该专用一个线程来进行信号处理。您分四个步骤进行操作:

  1. main中,在创建任何线程之前,请使用pthread_sigmask来阻止所有信号,但那些信号指示同步致命事件(SIGABRT,SIGBUS,SIGFPE,SIGILL,SIGSEGV ,SIGSYS和SIGTRAP)。不要安装任何信号处理程序。
  2. 使用专用于信号处理的线程过程创建一个线程。
  3. 该线程循环调用sigwaitinfo以获取您关心的信号。这必须至少包括表示外部终止或挂起请求的信号:SIGINT,SIGHUP,SIGPWR,SIGQUIT,SIGTERM,SIGTSTP,SIGXCPU。如果使用子进程,则还必须包括SIGCHLD。
  4. 您的其他线程可以做任何他们需要做的事情而不必担心信号。他们可能会花费大部分时间进行计算或在select上进行封锁。