在一个程序收到某些信号后,程序都会自动去执行默认的操作,但大多的操作都会导致程序异常退出,除了前文我们介绍的阻塞信号以外,我们还可以对信号进行捕获(拦截)处理,让被捕获的信号去执行我们已经编写好的函数中,这样可以帮我们处理太多的问题。
C语言库函数中,提供了一个信号捕获函数,如下:
typedef void (*sighandler_t)(int) sighandler_t signal(int signum, sighandler_t handler
该函数的第一个参数是我们要发送的信号,第二个参数是让我们提供一个函数指针,这个函数指针的原型就是上面 typedef 的原型,我们根据原型定义一个函数,然后将函数名传递到第二个参数,就可以成功调用这个函数了。当函数执行成功,会将第一个参数中的信号捕获并让其指向我们自己编写的处理函数。具体代码如下:
#include <signal.h> #include <unistd.h> #include <stdio.h> // 自定义的信号处理函数 void mySigAction(int num) { printf("recv sig number %d, mySigAction function...\n", num); } int main(int argc, char* argv[]) { // 将 SIGINT 信号捕获,让程序接受到该信号后转到 mySigAction 函数 signal(SIGINT, mySigAction); while (1) { printf("mian printf...\n"); sleep(1); } return 0; }
以上代码执行的效果如下:
这是 C 语言库函数提供给我们的方法,除了这个方法外,我们还可以使用 linux/unix 系统提供给我们的系统函数来实现如上功能:
#include <stdio.h> #include <unistd.h> #include <signal.h> void dosig(int num) { printf("num = %d\n", num); printf("Hello itcast\n"); } int main(int argc, char* argv[]) { struct sigaction act, oldact; // 设定处理函数 act.sa_handler = dosig; // 如果不需要对新的阻塞列表进行修改,那么将这个掩码列表全部置零 sigemptyset(&act.sa_mask); // 设定捕获信号的处理方式为 sa_handler 方式 act.sa_flags = 0; // 捕获信号,并传递捕获后执行的操作结构体 sigaction(SIGINT, &act, &oldact); while (1) { printf("************\n"); sleep(1); } return 0; }
与 C 语言库函数一样,我们实现了同样的功能,但是系统函数的功能更加强大,他允许我们保存原有的信号处理过程的状态(sigaction第三个参数),如果需要恢复的时候,可以使用这个保存下来的结构体恢复到原来的信号处理过程。
除了这种处理方式以外,还有另外一种信号处理方式,这种方式允许我们接收发送信号进程的一些信息和传递数据,请参考:使用信号实现进程同步(踢皮球游戏)