如果信号的处理动作是用户自定义函数,则在信号传递时调用该函数,称为捕获信号。由于信号处理函数的代码在用户空间中,处理过程复杂,如下图所示:
sigaction与指定信号相关的处理动作可以读取和修改函数。
#include <signal.h>
int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);
act和oact指向:
strcut sigaction{
void (*sa_handler)(int); /* addr of signal handler, or SIG_IGN, or SIG_DFL */
sigset_t sa_mask; /* additional signals to block */
int sa_flags; /* signal options, Figure 10.16 */
void (*sa_sigaction)(int, siginfo_t *, void *);/* alternate handler */
};
当调用信号处理函数时,核心自动将当前信号添加到信号屏蔽字的过程中,当信号处理函数返回时返回时,原始信号屏蔽单词会自动恢复,以确保在处理信号时,如果信号再次产生,它将被阻塞到当前处理结束。如果在调用信号处理函数时,除了自动屏蔽当前信号外,还希望自动屏蔽其他信号sa_mask当信号处理函数返回时,需要额外屏蔽的信号会自动恢复原始信号屏蔽字。
更改SIGINT代码演示如下:
#include "./common/head.h" /*功能: *SIGINT最初的处理方法是终止过程,现在改变其处理方法,打印一句话。 */ void sig_int(int signo){ printf("get sig = %d, I am happy, I am alive\n", signo); return ; } int main() { strcut sigaction newact, oldact; //newact即将设置的处理方法,oldact用于保存当前的处理方法 newact.sa_handler = sig_int; //handler_func为自己写信号处理函数 sigemptyset(&newact.sa_mask); //将sa_mask清空,也就是SIGINT信号,其它信号不会被阻塞 newact.sa_flags = 0; //传0可以,需要了解每个宏定义 sigaction(SIGINT, &newact, &oldact); ///这句话执行后,收到SIGINT信号将执行handler_func函数 //在10s内,接收到SIGINT信号,都会执行handler_func函数 int n = 10; while(n--){ sleep(1); } sigaction(SIGINT, &oldact, NULL); //恢复现场,这句话执行后,接收到SIGINT信号,程序终止 return 0; }
pause在信号递达之前,使用调用过程悬挂函数。
#include <unistd.h>
int pause(void);
若信号的处理动作是终止过程,则过程终止,pause函数没有机会返回;如果忽略了信号的处理动作,过程将继续悬挂,pause不返回;如果信号处理动作是捕获,则调用信号处理函数pause返回-1,errno设置薇EINTR,表示被信号中断,所以pause只有错误的返回值(exec只有出错时才能返回)。
实现自己的sleep代码演示如下:函数:
#include "./common/head.h" /*功能: *实现自己的sleep功能。 *思路:改变SIGALRM信号的处理函数,处理函数什么都不做。设置闹钟,闹钟响时执行处理函数。 * pause设置闹钟后,函数负责挂起程序,等待信号到来。 */ //SIGALRM信号处理函数直接返回 void sig_alarm(int signo){ return; } unsigned int mysleep(unsigned int sec){ struct sigaction newact, oldact; newact.sa_handler = sig_alarm; sigemptyset(&newact.sa_mask); newact.sa_flags = 0; sigaction(SIGALRM, &newact, &oldact); //设置SIGALRM信号处理函数 alarm(sec); //设置sec闹钟,sec秒后,会发出SIGALRM此时将执行信号sig_alarm函数 pause(); //程序挂在这里,等待信号的到来 sigaction(SIGALRM, &oldact, NULL); //恢复现场 return alarm(0); //alarm(0)取消所有闹钟,回到最后一个闹钟还有多少s没有完成 } int main() { int n = 3; while(n--){ printf("eslape 1s\n"); mysleep(3); } return 0; }