跟着iMX28x开发套件学linux-06
六、linux应用编程之四:信号
linux同时运行着多个进程,进程通信就显得很有必要。实际上平时使用linux系统的时候也经常利用信号对进程进行通信,比如想要shell里终止一个正在运行的程序的时候,按下Ctrl+c的时候,等于向进程发送了一个SIGINT信号。
信号本身并不复杂,就是int类型的常量,用kill -l命令可以查看支持的信号。需要关注的是进程对信号的处理。当进程接收到信号,一般有三种响应方式:一是类似中断服务函数的响应方式;二是进程忽略信号,即不进行响应;三是系统默认的响应方式,一般是终止线程。
对于一般的信号,线程采用系统默认的响应方式即可,但是某些特别的情况下,系统默认的响应方式不能满足需求,那就需要自己编写响应函数,然后把该信号的响应方式设置为中断服务的响应方式,当然这里的中断服务函数要指向事先编写好的响应函数。
设置响应方式的函数为sigaction()函数,下面介绍这个函数。
sigaction()函数
1) 函数原型 : int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
2) 输入参数 : signum,哪个信号的响应要被设置;
*act,sigaction结构体的指针,用来配置设置项;
*oldact,sigaction结构体的指针,可以为NULL;
3) 返 回 值 : int,成功返回0,失败返回-1;
这个函数从表面看只是选定了要设置响应的信号,但是关于具体的设置并没有表现出来,比如要把中断服务函数设置成哪个响应函数,在处理选定的信号的时候要不要屏蔽一些信号等等。实际上这些内容都在sigaction结构体中。
sigaction结构体
1) *sa_handler : 函数指针,指向有一个int类型参数以及无返回值的函数。
2) *sa_sigaction : 同上,输入参数不同,指向更高级的响应函数,可以为空。
3) sa_mask : 屏蔽设置,设置哪些信号被屏蔽。
4) sa_flags : 响应选项,可以配置响应方式等的参数。
在实际使用的时候,先声明一个sigaction结构体,然后逐个初始化这个结构体的值。sa_handler就是指定信号发生时调用的函数的指针;sa_sigaction指向更高级的响应函数,前提是sa_flags要设置SA_SIGINFO;sa_mask可以调用 sigemptyset()、sigaddset()、sigdelset()分别对这个信号集进行清空、增加和删除被屏蔽信号的操作,将sa_mask的引用作为这三个函数的输入参数即可;sa_flags可以是多个配置选项的或,取值如下:
flags |
描述 |
SA_RESTART |
使被信号打断的系统调用自动重新发起。 |
SA_NOCLDSTOP |
使父进程在它的子进程暂停或继续运行时不会收到SIGCHLD 信号。 |
SA_NOCLDWAIT |
使父进程在它的子进程退出时不会收到 SIGCHLD 信号,这时子进程如果退出也不会成为僵尸进程。 |
SA_NODEFER |
使对信号的屏蔽无效,即在信号处理函数的执行期间仍能发出这个信号。 |
SA_RESETHAND |
信号被处理后重新设置处理方式到默认值。 |
SA_SIGINFO |
使用 sa_sigaction 成员而不是 sa_handler 作为信号处理函数。 |
使用Ctrl+c向程序发送SIGINT信号示例
#include <unistd.h> #include <stdio.h> #include <signal.h> //sa_handler function void ouch(int sig){ printf("\nOuch! I got a signal %d\n", sig); } int main(){ struct sigaction act; act.sa_handler = ouch; //link handler sigemptyset(&act.sa_mask); //empty signal mask act.sa_flags = SA_RESETHAND; //use default after due signal sigaction(SIGINT, &act, NULL); //use params to set signal action while(1){ printf("sleep(1)\n"); sleep(1); } return 0; }
运行结果:
父进程使用kill()向子进程发送信号示例
运行结果: