信号捕捉(拦截)

在一个程序收到某些信号后,程序都会自动去执行默认的操作,但大多的操作都会导致程序异常退出,除了前文我们介绍的阻塞信号以外,我们还可以对信号进行捕获(拦截)处理,让被捕获的信号去执行我们已经编写好的函数中,这样可以帮我们处理太多的问题。


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;
}

以上代码执行的效果如下:

2015-07-02_185950

这是 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;
}

2015-07-02_190601

与 C 语言库函数一样,我们实现了同样的功能,但是系统函数的功能更加强大,他允许我们保存原有的信号处理过程的状态(sigaction第三个参数),如果需要恢复的时候,可以使用这个保存下来的结构体恢复到原来的信号处理过程。

除了这种处理方式以外,还有另外一种信号处理方式,这种方式允许我们接收发送信号进程的一些信息和传递数据,请参考:使用信号实现进程同步(踢皮球游戏)

 

评论