1,在linux的信号机制里面,有很多信号的默认处理都是结束进程,例如SIGPIPE,SIGINT
如果我们没有对信号进行处理,那么我们的程序就不太健壮。
2,不同的操作系统,多线程中对信号的处理不一致。
linux的线程其实就是一个轻量级的进程,每一个线程都可以接收和处理信号。
例如,linux中信号处理默认是由主线程进行,但如果主线程对某个信号进行了屏蔽,这个信号就可以交给其它可以处理的线程进行处理。
3,为了统一,我们可以在主线程里面接收和处理信号,而其它线程屏蔽所有信号。
代码如下:
rbsignal.h
#ifndef _RB_SIGNAL_H #define _RB_SIGNAL_H #include <sys/signal.h> #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <unistd.h> #include <string.h> #include <sys/socket.h> void set_pipe(int p); //阻塞所有的信号 void block_all_signal(); //主线程信号处理 void main_thread_sig_hand(); //信号是否在信号掩码中 int is_member(int sig); #endif
rbsignal.cc
#include "rbsignal.h" static int rb_pipe; void set_pipe(int p) { rb_pipe = p; } //阻塞所有的信号 void block_all_signal() { sigset_t mask; sigfillset(&mask); int rc = pthread_sigmask(SIG_BLOCK, &mask, NULL); if (rc != 0) { fprintf(stderr, "block all signal error: %s\n", strerror(rc)); exit; } } //所有信号的处理函数 //就是向管道发一个信号值,以便在libevent循环中处理,目标:统一事件源 static void sig_handler(int sig) { int save_errno = errno; int msg = sig; int r = write(rb_pipe, (char*)&msg, 4); errno = save_errno; } //安装一个信号处理程序 static void add_signal(int sig) { struct sigaction action; memset(&action, 0, sizeof(action)); action.sa_handler = sig_handler; sigfillset(&action.sa_mask); sigaction(sig, &action, NULL); } //主线程的信号处理 void main_thread_sig_hand() { sigset_t except; sigemptyset(&except); sigaddset(&except, SIGHUP); sigaddset(&except, SIGPIPE); sigaddset(&except, SIGTERM); sigaddset(&except, SIGINT); int rc= pthread_sigmask(SIG_UNBLOCK, &except, NULL); if (rc != 0) { fprintf(stderr, "main thread signal error: %s\n", strerror(rc)); exit; } add_signal(SIGHUP); add_signal(SIGPIPE); add_signal(SIGTERM); add_signal(SIGINT); } //信号是否在信号掩码中 int is_member(int sig) { sigset_t old; pthread_sigmask(SIG_SETMASK, NULL, &old); return sigismember(&old, sig); }
以上两个文件是信号处理模块的相关接口,使用方法如下:
/*信号处理---在主线程生成多线程前阻塞所有信号,这样在子线程中可以继承主线程的信号处理,即阻塞所有信号*/ block_all_signal(); /*初始化线程池*/ thread_pool_init(thread_num);
/*为主线程添加信号处理---子线程生成完成后,再由主线程接收对信号的处理*/
int pipefd[2]; pipe(pipefd); set_pipe(pipefd[1]); main_thread_sig_hand();
//在libevent统一的事件处理中,对信号进行处理
//......
event_set(&sig_event,pipefd[0], EV_READ|EV_PERSIST, sig_callback, NULL);
//......
void sig_callback(int fd,short ev,void *arg) { char c[4]; read(fd, c ,4); int sig = *(int*)c; switch(sig) { case SIGHUP: fprintf(stderr,"receive SIGHUP\n"); break; case SIGINT: fprintf(stderr,"receive SIGINT\n"); break; case SIGTERM: fprintf(stderr,"receive SIGTERM\n"); break; case SIGPIPE: fprintf(stderr,"receive SIGPIPE\n"); break; } }
代码可以下载:https://github.com/hxdoit/real_time_rank/tree/master/server1-1.0 (整个服务端)
https://github.com/hxdoit/real_time_rank/blob/master/server1-1.0/rbsignal.h (信号相关的部分)
https://github.com/hxdoit/real_time_rank/blob/master/server1-1.0/rbsignal.cc (信号相关的部分)
https://github.com/hxdoit/real_time_rank/blob/master/server1-1.0/server.cc (信号相关的部分)