进程间通信之信号
关于UNIX环境高级编程和UNIX网络编程的学习记录和总结
信号量signal
信号量是一个计数器,用于多进程对共享数据对象的存取。信号自身不能携带大量信息,所以信号是作为一个标志位来传递信息的,只有在满足条件时才会被发送。
信号早期被称为软中断,一旦信号产生,无论程序执行到什么位置,必须立即停止运行转去处理信号,处理结束,再继续执行后续指令。
注:信号的产生和处理都是有内核完成
产生信号的方式大致有按键产生、系统调用产生 、软件条件产生 、硬件异常产生、使用命令产生
信号的处理方式: 执行默认处理动作、忽略、捕捉。
信号的使用
信号未到达之前称之为未决态,当信号到达时回直接被内核处理掉。多种信号构成一个信号集称,用来表示未到达的信号称为未决信号集,若将信号阻塞,则信号不能递达将一直处于未决态,相当于将之屏蔽,被阻塞的信号集又称为信号屏蔽字(用一个位图来表示)。
查看当前系统中可用信号(kill -l)
特殊:9号SIGKILL ,19号SIGSTOP 不能被忽略阻塞和捕捉,只能执行默认动作
10号SIGUSR1 ,12号SIGUSR2没有默认事件,但又默认动作为终止进程
17号SIGCHLD默认动作忽略这个信号
信号使用之前,应先确定其 4 要素,而后再用
4要素:编号、名称、对应事件、默认处理动作。
默认动作:
Term:终止进程
Ign: 忽略信号 (默认即时对该种信号忽略操作)
Core:终止进程,生成 Core 文件。 (查验进程死亡原因, 用于 gdb 调试)
Stop:停止(暂停)进程
Cont:继续运行进程
异常信号
除 0 操作 → 8) SIGFPE (浮点数例外) “F” -----float 浮点数。
非法访问内存 → 11) SIGSEGV (段错误)
总线错误 → 7) SIGBUS
使用kill命令来发送终止信号
int kill(pid_t pid, int signum)
参数:
pid: > 0:发送信号给指定进程
= 0:发送信号给跟调用kill函数的那个进程处于同一进程组的进程。
< -1: 取绝对值,发送信号给该绝对值所对应的进程组的所有组员。
= -1:发送信号给,有权限发送的所有进程。
signum:待发送的信号
返回值:
成功: 0
失败: -1 设置errno
信号集操作函数
sigset_t set; 自定义信号集。
sigemptyset(sigset_t *set); 清空信号集
sigfillset(sigset_t *set); 全部置1
sigaddset(sigset_t *set, int signum); 将一个信号添加到集合中
sigdelset(sigset_t *set, int signum); 将一个信号从集合中移除
sigismember(const sigset_t *set,int signum); 判断一个信号是否在集合中。 在--》1, 不在--》0
设置信号屏蔽字和解除屏蔽:
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
how: SIG_BLOCK: 设置阻塞
SIG_UNBLOCK: 取消阻塞
SIG_SETMASK: 用自定义set替换mask。
set: 自定义set
oldset:旧有的 mask。
查看未决信号集:
int sigpending(sigset_t *set);
set: 传出的 未决信号集。
信号操作流程:
- sigemptyset(&set)清空信号集;
- sigaddset(&set,SIGNUM)添加信号到信号集
- sigprocmask(int how, const sigset_t *set, sigset_t *oldset);设置屏蔽字
- sigpending(sigset_t *set);查看未决集
- 程序执行等待信号
信号捕捉(实现自定义)
signal()实现
typedef void(*sighandler_t)(int);
函数指针类型,传入函数名
参数:
signum :待捕捉信号
handler:捕捉信号后的操纵函数
信号捕捉期间:
- 执行自定义的sa_mask掩码直到捕捉函数执行结束恢复原mask
- 本信号自动被屏蔽
- 被屏蔽信号多次发送时,解除屏蔽后只处理一次
void sig_catch(int signo){
printf("catch you %d\n",signo);
return;
}
signal(SIGINT,sig_catch);//注册捕捉函数
signaction()实现
sa_mask信号屏蔽字,只工作于信号捕捉函数期间,之前的mask工作在整个进程,sa_mask相当于暂时覆盖mask,sa_flag=0(默认屏蔽)