pthreads中的信号处理
我创建了一个pthread,并在其中安装了一个信号处理程序,与main( )
函数中的方式相同。 线程的信号处理程序是一个单独的函数。 令人惊讶的是,它不起作用,即线程的信号处理程序无法捕获信号。
这是代码:
#include #include #include #include #include typedef struct data { char name[10]; int age; }data; void sig_func(int sig) { printf("Caught signal: %d\n",sig); signal(SIGSEGV,sig_func); } void func(data *p) { printf("This is from thread function\n"); signal(SIGSEGV,sig_func); // Register signal handler inside thread strcpy(p->name,"Mr. Linux"); p->age=30; sleep(2); // Sleep to catch the signal } int main() { pthread_t tid; pthread_attr_t attr; data *ptr; pthread_attr_init(&attr); pthread_create(&tid,&attr,(void*)func,ptr); pthread_kill(tid,SIGSEGV); pthread_join(tid,NULL); printf("Name:%s\n",ptr->name); printf("Age:%d\n",ptr->age); }
输出:
分段错误(这意味着信号不会被处理程序捕获)
您的代码有几个问题:
-
ptr
未初始化,因此所有ptr->
部件都会使程序崩溃 - 你很可能在安装信号处理程序之前立即调用
pthread_kill()
,并且在一个线程中(具有未指定的行为) - 你从一个信号处理程序调用
printf()
,这不能保证工作(参见man 7 signal
for a safe functions)
虽然你仍然需要正确的线程同步,并且如其他地方所述,你应该使用sigaction()
:
#include #include #include #include #include typedef struct data { char name[10]; int age; }data; void sig_func(int sig) { write(1, "Caught signal 11\n", 17); signal(SIGSEGV,sig_func); } void func(data *p) { fprintf(stderr, "This is from thread function\n"); strcpy(p->name,"Mr. Linux"); p->age=30; sleep(2); // Sleep to catch the signal } int main() { pthread_t tid; pthread_attr_t attr; data d; data *ptr = &d; signal(SIGSEGV,sig_func); // Register signal handler before going multithread pthread_attr_init(&attr); pthread_create(&tid,&attr,(void*)func,ptr); sleep(1); // Leave time for initialisation pthread_kill(tid,SIGSEGV); pthread_join(tid,NULL); fprintf(stderr, "Name:%s\n",ptr->name); fprintf(stderr, "Age:%d\n",ptr->age); }
编辑 :在主线程中安装sighandler
我认为问题的核心是信号作为一个整体传递给整个过程,而不是单个线程。 通常,提名单个线程来处理所有信号; 所有其他线程(包括主线程)需要使用pthread_sigmask()
来阻塞信号 。
您可以设置掩码以阻止所有信号,启动信号处理程序线程,取消屏蔽您希望处理的信号,然后返回主线程,启动您需要的所有其他线程。 他们将从主线程inheritance“阻止所有信号”掩码。
顺便说一下,是时候离开signal(3)
并切换到sigaction(2)
,它具有可靠的语义并且更好地标准化。 (因此更便携。)
你没有提到的代码的一个问题是,虽然信号阻塞(和交付,如果你使用pthread_kill
或raise
)是每个线程,信号处理程序是每个进程。 这意味着它们是线程间通信的一种非常糟糕的机制,特别是如果你的代码将被用作库代码,因为对于库来说改变调用者的信号处理程序是非常糟糕的行为。
还要注意,与其他线程信号方法(如条件变量或障碍)相比,使用信号处理程序进行线程之间的通信具有次优性能,因为至少有一个额外的用户 – 内核 – 用户转换(当信号处理程序返回时)。