信号:告知某个进程某个事件的发生,也被称为软中断.
信号的来源:a.由一个进程发给另一个进程(或者自身)
b.由内核发给某个进程
信号的处理:称为行为,是一个被称为信号处理函数的函数,这种行为称为捕获信号(SIGKILL和SIGSTOP)不能被捕获
SIGIGN也是一种信号处理的方式,代表忽略
为信号设置处理函数的流程
using handleFunc = void (int);
handleFunc* sigSetFunc(handleFunc * seted,int sig)
{
接受设置前的信号
struct sigaction act,oact;
///设置信号处理函数
act.sa_handler = seted;
POSIX允许设置当信号处理函数调用时阻塞的信号
将该集合设置为空,代表处理时不阻塞其他信号的接受
POSIX保证当前处理函数运行时捕获的信号永远是阻塞的
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
///若是定时器信号
if(sig == SIGALRM){
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT;
#endif
}
else{
#ifdef SA_RESTART
///SA_RESTART的作用:在执行阻塞的系统调用时,若收到信号
///那么默认会退出,SA_RESTART则是重新执行该阻塞的系统调用
///使得程序不会过早的意外退出
act.sa_flags |= SA_RESTART;
#endif
}
if(sigaction(sig,&act,&oact) < 0){
return (SIG_ERR);
}
return oact.sa_handler;
}
处理SIGCHLD信号!!!
在任何fork了子进程的程序中,我们必须要执行wait(防止僵尸进程一直占用内核空间),但是wait的时机却是不明朗的,因此最好的解决方案是处理SIGCHLD函数.
void handleChild(int sigNo){
pid_t pid;
int stat;
///结束的子进程被合适的释放内核空间
pid = wait(&stat);
return;
}
wait函数和waitpid函数
wait原型为
extern __pid_t wait (int *__stat_loc);
用于回收已经终止子进程的内核分配资源 ,stat_loc将返回子进程是如何终止的,如果确实有子进程并且子进程还未终止,那么将会阻塞直到有子进程终止
waitpid原型
extern __pid_t waitpid (__pid_t __pid, int *__stat_loc, int __options);
和wait相比能够指定子进程的pid,option常用的选项是WNOHANG,代表不会被阻塞
日常中应该使用wait_pid函数,原因:
1.wait是阻塞的,而且当多个信号同时到达时,收到的该信号数量是不一定的(POSIX带来的坏处,没有信号排队机制),这时候要使用非阻塞的wait_pid保证所有的子进程终止都被正确处理
void handleChild(int sigNo){
pid_t pid;
int stat;
///结束的子进程被合适的释放内核空间
while((pid = waitpid(-1,&stat,WNOHANG))>0 ){
;
}
return;
}
SIGPIPE信号
对于一个对方已经关闭的连接,调用send会受到一个RST,对于一个已经发送过RST的对端再次调用send,将会得到一个SIGPIPE信号,该信号不被处理将会直接导致程序的终结