簡體   English   中英

用進程和2個線程在C中進行信號處理不起作用

[英]Signal handling in C with process and 2 threads doesn't work

我正在使用以下示例(該示例基於linux中pthread_sigmask的手冊頁中的示例):

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <string.h>

/* Simple error handling functions */

#define handle_error_en(en, msg) \
        do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

static void * silly_worker(void *arg)
{
  for(int index=0,max=5; index<max; ++index) {
    printf("waiting %d of %d\n",index,max);
    sleep(1);
  }
  puts("Finished waiting.  Here comes the SIGSEGV");
  strcpy(NULL,"this will crash");
}

static void *
sig_thread(void *arg)
{
    sigset_t *set = (sigset_t *) arg;
    int s, sig;

    for (;;) {
        s = sigwait(set, &sig);
        if (s != 0)
            handle_error_en(s, "sigwait");
        printf("Signal handling thread got signal %d\n", sig);
    }
}

int
main(int argc, char *argv[])
{
    pthread_t thread;
    pthread_t thread2;
    sigset_t set;
    int s;

    /* Block SIGINT; other threads created by main() will inherit
       a copy of the signal mask. */

    sigemptyset(&set);
    sigaddset(&set, SIGQUIT);
    sigaddset(&set, SIGUSR1);
    sigaddset(&set, SIGSEGV);
    s = pthread_sigmask(SIG_BLOCK, &set, NULL);
    if (s != 0)
        handle_error_en(s, "pthread_sigmask");

    s = pthread_create(&thread, NULL, &sig_thread, (void *) &set);
    if (s != 0)
        handle_error_en(s, "pthread_create");

    /* Main thread carries on to create other threads and/or do
       other work */

    s = pthread_create(&thread2, NULL, &silly_worker, (void *) &set);
    if (s != 0)
        handle_error_en(s, "pthread_create");

    pause();            /* Dummy pause so we can test program */
}

根據手冊頁,這應該捕獲由silly_worker線程生成的SIGSEGV。 但事實並非如此。 實際上,我不確定是什么機構正在發出信號。 當程序運行時,我得到以下輸出:

waiting 0 of 5
waiting 1 of 5
waiting 2 of 5
waiting 3 of 5
waiting 4 of 5
Finished waiting.  Here comes the SIGSEGV
Segmentation fault

您會看到信號處理程序沒有輸出“ Segmentation fault”字符串,因此它必須來自默認處理程序。 如果是默認值,則可能會破壞示例的目的-設置信號處理程序並捕獲信號並對它們執行某些操作。

我可以找到很多處理程序的示例,但是沒有一個適用於這種情況:它們都沒有演示導致真正明顯的SIGSEGV的線程,並在其自定義處理程序中捕獲並報告了錯誤。

問題仍然存在:如何獲取自定義信號處理程序以從該SIGSEGV線程獲取信號?

來自無效內存訪問的SIGSEGV (與killsigqueue發送的“假”消息相反)被發送到執行無效內存訪問的線程,而不是整個進程。 因此,您無法擁有專用的段故障處理程序線程。 如果要處理它,則必須在發生它的線程中處理它。 (看到shell print Segmentation fault的原因是,當SIGSEGV被阻塞在線程中並且發生Segmentation fault時,內核會執行默認的殺死進程的動作。實際上,它是每個POSIX的UB,但這是Linux處理的方式UB。)

但是請注意,您可以讓SIGSEGV的信號處理程序通過專用線程觸發操作。 這樣做的一種丑陋方法是使用另一個信號,您可以通過sigqueue發送(連同參數一起)。 更干凈的方法(至少在我看來)是使SIGSEGV處理程序使用sem_post ,它是異步信號安全的,可用於喚醒另一個正在等待信號量的線程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM