1.Linux 信号是一种异步机制,进程可以接收一个信号,并有相应的处理操作,如果我们需要改变当该信号发生时的默认行为,我们就需要捕捉该信号,并且自己书写信号处理函数。
2.这种信号处理函数就跟中断差不多,当一个进程接收到一个信号时,进程会暂停当前的执行流,转而调用信号处理函数,信号处理函数结束之后,会继续刚才的执行流继续执行。
3.如果进程已经阻塞在一些系统调用的时候,信号发生之后,是不会重新调用这些系统调用的,但是也可以设置成继续进行这些系统调用。
我们可以使用sigaction函数来对一个信号进行捕捉,并且指定这个信号的处理函数。这个是POSIX.1标准,如果在不支持POSIX.1的系统上面,那么还是需要调用signal这个标准C函数。
对于信号处理函数是否可以接收参数来说,我们可以把信号处理函数分成两种:一种可以接收用户发送过来的数据,另外一种不能得到用户发送过来的数据。
① 不能接收用户发送过来的数据:
int firstFunc(int signo) {
printf("In the handler");
}
struct sigaction newAction, oldAction;
memset(&newAction, 0, sizeof(newAction))
newAction.sa_flag = 0;
newAction.sa_handler = firstFunc;
sigemptyset(&sa_mask)
sigaction(SIGINT, &newAction, &oldAction)
这样,当此进程收到SIGINT信号的时候,就会调用firstFunc函数,调用完毕之后会继续主函数的执行流。
② 可以接收用户发送过来的数据:
有时候我们想在这个信号发生的时候,传递一些我们需要的信息到信号处理函数里面,这个时候我们就需要用另外一种方式:
int secondFunc(int signo, siginfo* info, void* context) { // (1)
Data* data = (Data*)info->si_value.sival_ptr;
/*Deal with data......*/
}
struct sigaction newAction, oldAction;
memset(&newAction, 0, sizeof(newAction))
newAction.sa_flag = SA_SIGINFO; // (2)
sigemptyset(&newAction.sa_mask);
newAction.sa_sigaction = secondFunc; // (3)
Data* data;
/*Construct your data struct.*/
union sigval curVal;
curVal.sival_ptr = (void*)data;
sigqueue(getpid(), SIGINT, curVal); // (4)
上面需要注意的就是4点:
(1)这个是信号处理函数的原型,多出来了两个参数。只能这样写。
(2)需要在sigaction里面的sa_flag 添加SA_SIGINFO,表示我们会传递一些信息到错误处理函数里面。
(3)使用SA_SIGINFO之后,我们需要使用sa_sigaction这个成员变量,而不是sa_handler。
(4)我们需要使用sigqueue函数来对特定的进程发送特定的信号,并且curVal这个联合体里面携带了我们需要传递的数据的指针。
两种方式需要按照特定的需求来选用。