[英]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
(與kill
或sigqueue
發送的“假”消息相反)被發送到執行無效內存訪問的線程,而不是整個進程。 因此,您無法擁有專用的段故障處理程序線程。 如果要處理它,則必須在發生它的線程中處理它。 (看到shell print Segmentation fault
的原因是,當SIGSEGV
被阻塞在線程中並且發生Segmentation fault
時,內核會執行默認的殺死進程的動作。實際上,它是每個POSIX的UB,但這是Linux處理的方式UB。)
但是請注意,您可以讓SIGSEGV
的信號處理程序通過專用線程觸發操作。 這樣做的一種丑陋方法是使用另一個信號,您可以通過sigqueue
發送(連同參數一起)。 更干凈的方法(至少在我看來)是使SIGSEGV
處理程序使用sem_post
,它是異步信號安全的,可用於喚醒另一個正在等待信號量的線程。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.