linux高级编程-信号(2)-信号处理函数的注册方式
信号处理函数的注册有两种方式,分别是简单版(signal)和高级版(sigaction)
简单版-signal():
sighandler_t signal(int signum, sighandler_t handler);
函数描述:signal() sets the disposition of the signal signum to handler,意思就是给信号设置处理函数
参数signum:需要设置处理函数的信号
参数handler:信号处理函数地址
函数返回值:returns the previous value of the signal handler, or SIG_ERR on error,返回之前的处理方式,或返回错误
函数的使用:
1 /** 2 * @brief handle : User-defined signal processing function 3 * @param sig 4 */ 5 void handle(int sig) 6 { 7 std::cout << " handle signal ******* " << sig << std::endl; 8 } 9 10 int main(int argc, char *argv[]) 11 { 12 // 注册自定义信号处理函数 13 if (SIG_ERR == signal(SIGINT, handle)) { 14 std::cout << " Failed to registered handle ******* " << SIGINT << std::endl; 15 return 0; 16 } 17 18 // 将信号设置为默认处理方式 19 if (SIG_ERR == signal(SIGTERM, SIG_DFL)) { 20 std::cout << " Failed to registered handle ******* " << SIGTERM << std::endl; 21 return 0; 22 } 23 24 for (;;) {sleep(1);} 25 }
运行结果查看:

通过运行结果查看,可以看出当按下 ctrl + c 的时候都会执行自定义信号处理函数
高级版的使用-sigaction():
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
函数描述:
参数signum:需要处理的信号
参数act和参数oldact:If act is non-NULL, the new action for signal signum is installed from act. If oldact is non-NULL, the previous action is saved in oldact
struct sigaction {
void (*sa_handler)(int); //信号处理程序,不接受额外数据,SIG_IGN 为忽略,SIG_DFL 为默认动作
void (*sa_sigaction)(int, siginfo_t *, void *); //信号处理程序,能够接受额外数据和sigqueue配合使用
sigset_t sa_mask;//阻塞关键字的信号集,可以再调用捕捉函数之前,把信号添加到信号阻塞字,信号捕捉函数返回之前恢复为原先的值。
int sa_flags;//影响信号的行为SA_SIGINFO表示能够接受数据
};
基本使用 ( 只用来注册信号处理函数,效果与signal()一样 ) 代码如下:
1 #include <iostream> 2 #include <signal.h> 3 #include <unistd.h> 4 5 /** 6 * @brief handle : User-defined signal processing function 7 * @param sig 8 */ 9 void handle(int sig) 10 { 11 for (int i = 0; i < 20; i++) { 12 std::cout << " handle signal ******* " << sig << std::endl; 13 sleep(1); 14 } 15 } 16 17 int main(int argc, char *argv[]) 18 { 19 struct sigaction act, oldact; 20 act.sa_handler = handle; 21 sigaction(SIGINT, &act, &oldact); 22 23 for (;;) {sleep(1);} 24 }
sigaction中sa_mask的使用:
sa_mask的作用是用来设置在处理该信号时暂时将sa_mask 指定的信号搁置,也就是sa_mask指定的信号会被阻塞,直到sa_handler指向的处理函数执行完毕才会解除阻塞,举例说明:
先看如下代码:
1 #include <iostream> 2 #include <signal.h> 3 #include <unistd.h> 4 5 void handleINT(int sig) 6 { 7 for (int i = 0; i < 20; i++) { 8 std::cout << " handleINT ******* " << sig << std::endl; 9 sleep(1); 10 } 11 } 12 13 void handleTERM(int sig) 14 { 15 for (int i = 0; i < 5; i++) { 16 std::cout << " handleTERM ******* " << sig << std::endl; 17 sleep(1); 18 } 19 } 20 21 int main(int argc, char *argv[]) 22 { 23 struct sigaction act, oldact; 24 act.sa_handler = handleINT; 25 // sigaddset(&act.sa_mask, SIGTERM); // 用来设置在处理该信号时暂时将sa_mask 指定的信号搁置 26 sigaction(SIGINT, &act, &oldact); 27 28 // registered SIGTERM 29 signal(SIGTERM, handleTERM); 30 31 for (;;) {sleep(1);} 32 }
代码的执行结果如下所示:

在发送SIGINT信号之后发送SIGTERM信号(此时SIGINT信号的处理函数还在执行),我们发现SIGINT信号的处理函数被中止,而去执行SIGTERM的处理函数,等到SIGTERM的处理函数执行结束之后再回过头执行SIGINT的处理函数。
如果我们使用了sa_mask了呢?,先看下方代码(注意与上面代码的不同之处):
1 #include <iostream> 2 #include <signal.h> 3 #include <unistd.h> 4 5 void handleINT(int sig) 6 { 7 for (int i = 0; i < 20; i++) { 8 std::cout << " handleINT ******* " << sig << std::endl; 9 sleep(1); 10 } 11 } 12 13 void handleTERM(int sig) 14 { 15 for (int i = 0; i < 5; i++) { 16 std::cout << " handleTERM ******* " << sig << std::endl; 17 sleep(1); 18 } 19 } 20 21 int main(int argc, char *argv[]) 22 { 23 struct sigaction act, oldact; 24 act.sa_handler = handleINT; 25 sigaddset(&act.sa_mask, SIGTERM); // 用来设置在处理该信号时暂时将sa_mask 指定的信号搁置 26 sigaction(SIGINT, &act, &oldact); 27 28 // registered SIGTERM 29 signal(SIGTERM, handleTERM); 30 31 for (;;) {sleep(1);} 32 }
上面代码的执行效果如下所示,步骤与不使用sa_mask的一样

使用sa_mask后,在发送SIGINT信号之后发送SIGTERM信号(此时SIGINT信号的处理函数还在执行),我们发现SIGINT信号的处理函数不会被中止,而SIGTERM的处理函数只有在SIGINT信号的处理函数执行结束之后才会执行。 也就是sa_mask指定的信号不会中断sa_handler函数。
sigaction中sa_flags的使用:sa_flags的常用取值如下所示
| 取值 | 功能描述 |
| SA_SIGINFO | 说明了信号处理程序带有附加信息,也就是会调用 sa_sigaction 这个函数指针所指向的信号处理函数。在此,还要特别说明一下,sa_sigaction 和 sa_handler 使用的是同一块内存空间,相当于 union,所以只能设置其中的一个,不能两个都同时设置 |
| SA_INTERRUPT | 信号中断程序执行完毕之后,之前的系统调用会继续之心 |
| SA_RESTART | 信号中断程序执行完毕之后,之前的系统调用会继续之心 |
| SA_NOCLDSTOP | 一般当进程终止或停止时都会产生SIGCHLD信号,但若对SIGCHLD信号设置了该标志,则子进程停止时不产生此信号,终止时才产生此信号 |
| SA_RESETHAND | 当调用信号处理函数时,将信号的处理函数重置为缺省值SIG_DFL |
sigaction中sa_flags设置为SA_SIGINFO,也就是向信号处理函数中传递附加信息
如果想将参数也传递到信号处理函数里面,需要用到sigqueue函数发送信号,代码如下图所示:
1 #include <iostream> 2 #include <signal.h> 3 #include <unistd.h> 4 5 // 三参数信号处理函数的实现 ********************************** 6 void handle(int signum, siginfo_t *info, void *myact) //三参数信号处理函数的实现 7 { 8 std::cout << "signum ************* " << signum << std::endl; 9 std::cout << "info **************** " << (char *)((*info).si_ptr) << std::endl; 10 } 11 12 int main(int argc, char *argv[]) 13 { 14 struct sigaction act, oldact; 15 act.sa_sigaction = handle; //三参数信号处理函数 16 act.sa_flags = SA_SIGINFO; 17 sigaction(SIGTERM, &act, &oldact); 18 19 pid_t pid = getpid(); 20 union sigval info; 21 char ch[] = "Info from handle"; 22 info.sival_ptr = ch; 23 24 for (;;) { 25 sigqueue(pid, SIGTERM, info); //向本进程发送信号,并传递附加信息 26 sleep(2); 27 } 28 }
运行结果如下图所示:

sa_flags其它取值使用不多暂不研究。
浙公网安备 33010602011771号