1.基本概念
信号是事件发生时对进程的通知机制,一个进程可以想另一个进程发送信号,此做法可以实现进程间的同步,然而给进程发信号的通常都是内核
(1)内核一般都会在发生以下事件时给进程发信号 .硬件发生异常 .用户键入了能够产生信号的终端特殊字符 .发生了软件事件 针对每一个信号,都定义了一个唯一的整数
(2)如果内核要调度该进程,等待信号就会马上送达,然而有时进程不想中断代码,进程可以将该信号添加到进程的信号掩码中,此信号将处于等待状态,知道进程将其从信号掩码中解除出来
(3)信号到达后,进程根据具体信号执行如下操作 .忽略信号:内核将信号丢弃,信号对进程不产生影响终止进程:进程异常终止 .停止进程:暂停进程的执行
具体的信号都是由信号处理函数来执行的
2.信号类型和默认行为
信号名称 描述
SIGABRT 终止进程
SIGALRM 实时定时器过期
SIGBUS 内存访问出错
SIGCHLD 终止子进程
SIGCONT 若停止则继续
SIGEMT 硬件错误
SIGFPE 算数异常
SIGHUP 刮起
SIGTLL 非法指令
SIGINT 终端中断
SIGIO I/0时可能产生
SIGKILL 必杀
SIGPIPE 管道断裂
SIGPROF 性能分析定时器过时
SIGQUIT 终端退出
SIGSEGV 无效的内存访问
SIGSTKFLT 协议处理栈错误
SIGSTOP 确保停止
SIGSYS 无效的系统调用
SIGUSR 用户自定义信号
3.自定义信号处理函数signal()#include<signal.h>sighandler_t signal(int sig,sighandler_t handler);
第一个参数sig,标注希望修改的信号编号,第二个参数handler,则指明信号到达时,所调用的处理函数,,singal的返回值为之前改信号的处理函数 特别注意:我们可以用SIG_IGN来取代handler参数,它的作用是忽略该信号,如果信号专为此进程而生,则内核会丢弃此信号
4.信号处理器
信号处理器程序(信号捕捉器)是指当指定信号传递给进程时会调用一个函数 调用信号处理器程序会打断主程序流程,内核代表进程来处理程序,当处理完之后,主程序会从打断的位置恢复执行
具体实例sigHanler(int sig){printf(“hello,world\n”);}int main(){int i;if(signal(SIGINT,sigHanler) == SIG_ERR){printf(“error\n”);}for(i=0;i<3;i++){printf(“haha\n”);sleep(2);}}
运行结果如下:
5.发送信号:kill()#include<signal.h>int kill(pid_t,int sig);//成功返回0,失败-1
该调用将会杀掉指定pid的进程,sig则指定了要发送的信号 .如果pid大于0,那么信号发给pid指定的进程 .pid等于0发给同组的每个进程 .pid小于-1,发送给pid绝对值下属的所有进程 .pid等于-1,调用进程有权将信号发给每个进程
6.用kill()检查进程的存在
若将sig参数置为0,则无信号发送,相反kill()仅回去执行错误检查,查看是否可以向进程发送信号。这意味着,可以用其来检查一个进程是否存在,若调用成功那么进程存在。但是这并不能保证该pid的进程就一定存在,有可能该pid指的进程已不是先前的那个进程了
判断进程存在与否的其他方法: (1)wait()系统调运:监控子进程是否存在 (2)信号量和文件锁:如果进程持有这些,那么如果不能取得这些,就以为这进程存在 (3)/proc/PID接口:如果进程存在,目录proc/12345将存在
7.显示信号描述#include<signal.h>char *strsignal(int sig);//返回可打印字符串8.信号集
当系统调用需要一组不同的信号时,就用到了信号集,信号集的数据结构为sigset_t (1)信号集的初始化
#include<signal.h>int sigemptyset(sigset_t *set);
(2)向set中添加或删除单个信号
#include<signal.h>int sigaddset(sigset_t *set,int sig);int sigdelset(sigset_t *set,int sig);
(3)判断sig是否在set中
#include<signal.h>int sigismember(const sigset_t *set,int sig);9.信号掩码
内核会为每个进程维护一个信号掩码,即一组信号,并将阻塞其对进程的传递。如果将遭阻塞的信号发送给进程,对该信号的传递将延后,直至从信号掩码中移除该信号
sigprocmask系统调用:
#include<signal.h>int sigprocmask(int how,const sigset_t *set,sigset_t *oldset);
sigprocmask()调运即可修改进程的信号掩码,又可获取现有掩码,或者俩重功效兼具,how参数指定给信号掩码带来的变化
how参数 具体描述
SIG_BLOCK 将set指向信号集中的指定信号添加到信号掩码中
SIG_UNBLOCK 将set指向信号集中的信号从信号掩码中删除
SIG_SETMASK 将set指向的信号集赋给信号掩码
10.等待状态的信号以及排队
若进程接收了一个正在阻塞的信号,则它会将该信号添加到进程的等待信号集中,不管该信号被发了多少此,在该信号被解除阻塞时,都只会给进程传递一次
11.改变信号处置:sigaction()sigaction *act,struct sigaction *oldact);
.sig参数标识想要获取或改变的信号编号 .act参数是指针,指向描述信号新处置的数据结构 .oldact参数用来返回之前信号处置的相关信息,若不想获取设为NULL sigaction结构定义如下
struct sigaction{void (*sa_handle)(int);sigset_t sa_mask;int sa_flags;void (*sa_restorer)(void);//不给应用程序使用}
其中sa_flags字段是一个位掩码,指定用于控制信号处理过程的各种选项(可以相或)
sa_flag字段 具体描述
SA_NOCLDSTOP 若sig为SIGCHLD(终止子进程),则恢复或停止子进程时,将不再产生此信号
SA_NOCLDWAIT 若sig为SIGCHLD信号,则当子进程终止时,不会将其转换为僵尸
SA_NODEFEP 捕获该信号时,不会在执行处理器程序时将该信号自动添加到进程掩码中
SA_ONSTACK 针对此信号调用处理器函数时,使用了由sigaltstack()安装俄被选栈
SA_RESTART 自动重启由信号处理器程序中断的系统调用
12.pause()#include<unistd.h>int pause(void)
调用pause()函数将暂停进程的执行,直至信号处理函数中断该调用为止
走自己的路,让人家去说吧。