1. 阻塞,sigaction函数有阻塞的功能,比如SIGINT信号来了,进入信号处理函数,默认情况下,在信号处理函数未完成之前,如果又来了一个SIGINT信号,其将被阻塞,只有信号处理函数处理完毕,才会对后来的SIGINT再进行处理,同时后续无论来多少个SIGINT,仅处理一个SIGINT,sigaction会对后续SIGINT进行排队合并处理。
2. sa_mask,信号屏蔽集,可以通过函数sigemptyset/sigaddset等来清空和增加需要屏蔽的信号,上面代码中,对信号SIGINT处理时,如果来信号SIGQUIT,其将被屏蔽,但是如果在处理SIGQUIT,来了SIGINT,则首先处理SIGINT,然后接着处理SIGQUIT。
3. sa_flags如果取值为0,则表示默认行为。还可以取如下俩值,但是我没觉得这俩值有啥用。
- SA_NODEFER,如果设置来该标志,则不进行当前处理信号到阻塞
- SA_RESETHAND,如果设置来该标志,则处理完当前信号后,将信号处理函数设置为SIG_DFL行为
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void sig_handler(int sig) {
// printf("receive : %d,thread id :%d", sig, pthread_self());
fprintf(stdout,"receive : %d,thread id :%d\n", sig, pthread_self());
int i = 0;
while (i < 5) {
fprintf(stdout,"%d\n", i);
sleep(1);
i++;
}
}
int main(int argc, char **argv) {
struct sigaction sa;
sa.sa_handler = sig_handler;
sa.sa_flags = 0 ;
sigaction(SIGINT, &sa, NULL);
printf("current thread:%d\n",pthread_self());
while (1){
sleep(1);
}
return 0;
}
- 当sa.sa_flags = 0 时当第一次按crtl+c 进入信号函数,接着在信号函数处理期间按多次crtl+c将合并成一次调用。
- 当sa.sa_flags = SA_NODEFER时信号函数时并发重入的,即按多少次crtl+c就立即进入几次。
- sa.sa_flags = SA_RESETHAND时当一次执行信号函数期间按多次crtl+c是忽略的,第一次执行完后会设置为SIG_DFL即原始的crtl+c操作也就是退出。
- sa.sa_flags = SA_NODEFER|SA_RESETHAND第一次产生ctrl+c信号的时候,该信号被自己设定的信号处理函数进行了处理。在处理过程中,由于我们设定了SA_RESETHAND标志位,又将该信号的处理函数设置为默认的信号处理函数(系统默认的处理方式为INT),所以在第二次发送ctrl+c信号的时候,是由默认的信号处理函数处理的,导致程序结束。
所以线上的信号函数可以设置成如下安全退出程序:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void sig_handler(int sig) {
app.stop();
exit(0);
}
int main(int argc, char **argv) {
struct sigaction sa;
sa.sa_handler = sig_handler;
sa.sa_flags = 0 ;
sigaction(SIGINT, &sa, NULL);
sleep(100);
return 0;
}