一、信号
信号特点:
1. 简单、不能携带大量信息、满足条件才发送。
2. 信号是软件层面上的“中断”。一旦信号产生,无论程序执行到什么位置,必须立即停止运行,处理信号,处理结束,再继续执行后续指令。
所有信号的产生及处理全部都是由【内核】完成的。
信号相关的概念:
产生信号:
1. 按键产生
2. 系统调用产生
3. 软件条件产生
4. 硬件异常产生
5. 命令产生
概念:
未决:产生与递达之间状态。
递达:产生并且送达到进程。直接被内核处理掉。
信号处理方式: 执行默认处理动作、忽略、捕捉(自定义)
阻塞信号集(信号屏蔽字): 本质:位图。用来记录信号的屏蔽状态。一旦被屏蔽的信号,在解除屏蔽前,一直处于未决态。
未决信号集:本质:位图。用来记录信号的处理状态。该信号集中的信号,表示,已经产生,但尚未被处理。
信号4要素:
编号、名称、对应事件、默认处理动作。
信号集操作函数:
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: 传出的 未决信号集。
信号捕捉:
signal();
sigaction();
信号捕捉特性:
1. 捕捉函数执行期间,信号屏蔽字 由 mask --> sa_mask , 捕捉函数执行结束。 恢复回mask
2. 捕捉函数执行期间,本信号自动被屏蔽(sa_flgs = 0).
3. 捕捉函数执行期间,被屏蔽信号多次发送,解除屏蔽后只处理一次!
二、使用信号进行父子进程间通信的案例
该案例中,父进程捕捉子进程死亡后发出的SIGCHLD信号,并使用自定义的信号处理函数处理该信号
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/wait.h>
void sys_err(const char *str)
{
perror(str);
exit(1);
}
//定义信号处理函数
void catch_child(int signo)
{
pid_t wpid;
int status;
//while((wpid = wait(NULL)) != -1)
while((wpid = waitpid(-1, &status, 0)) != -1) //循环回收,防止出现僵尸进程
{
if(WIFEXITED(status))
printf("-------------catch child id %d\n", wpid);
}
return;
}
int main(int argc, char *argv[])
{
pid_t pid;
//阻塞
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGCHLD);
sigprocmask(SIG_BLOCK, &set, NULL);
int i;
for(i = 0; i<15; i++)
{
if((pid = fork()) == 0) break;
}
if(15 == i)
{
struct sigaction act;
act.sa_handler = catch_child; //设置回调函数
sigemptyset(&act.sa_mask); //设置捕捉函数执行期间屏蔽字
act.sa_flags = 0; //设置默认属性,本信号自动屏蔽
sigaction(SIGCHLD, &act, NULL); //注册捕捉信号函数
//解除阻塞
sigprocmask(SIG_BLOCK, &set, NULL);
printf("-----I'm parent,pid = %d\n", getpid());
while(1);
}
else
{
printf("I'm child pid = %d\n", getpid());
sleep(1);
}
return 0;
}
执行结果:
I'm child pid = 7344
I'm child pid = 7343
I'm child pid = 7345
I'm child pid = 7346
I'm child pid = 7347
I'm child pid = 7348
I'm child pid = 7349
I'm child pid = 7350
I'm child pid = 7353
I'm child pid = 7351
-----I'm parent,pid = 7342
I'm child pid = 7356
I'm child pid = 7352
I'm child pid = 7354
I'm child pid = 7355
I'm child pid = 7357
-------------catch child id 7343
-------------catch child id 7344
-------------catch child id 7346
-------------catch child id 7347
-------------catch child id 7348
-------------catch child id 7345
-------------catch child id 7349
-------------catch child id 7353
-------------catch child id 7350
-------------catch child id 7351
-------------catch child id 7352
-------------catch child id 7354
-------------catch child id 7355
-------------catch child id 7356
-------------catch child id 7357