7.1 信号的概念
什么是信号:
信号是UNIX系统响应某些状况而产生的事件,进程在接收到信号时会采取相应的行动。
信号的特点:
简单,不能携带大量信息,满足特定条件才会发生。信号也叫软中断,有可能会有延迟。
信号的实现机制:
信号实际上是由内核发送,内核来处理收到的信号。收到信号的进程,必须对信号做出处理(忽略,捕获,默认动作都行)
信号的产生:
信号状态:
产生 递达:信号被捕捉并处理 未决:信号被阻塞
信号四要素:
编号、事件、名称、默认处理动作
7.2 进程处理信号行为
代码语言:javascript复制1、默认动作
2、忽略
3、捕捉
(后面两种处理行为就需要涉及到信号集了)
7.3 信号集处理函数
(1)首先要了解什么是信号集:
代码语言:javascript复制信号集被定义为一种数据类型:
typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t
//信号集用来描述信号的集合,每个信号占用一位(64位)。
//Linux所支持的所有信号可以全部或部分的出现在信号集中,主要与信号阻塞相关函数配合使用。
//下面是为信号集操作定义的相关函数:
#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);
(2)信号集处理函数:
那我们一个一个来看
int sigemptyset(sigset_t *set); //清空信号集嘛,传参传什么也应该很清楚了 初始化由set指定的信号集,信号集里面的所有信号被清空,相当于64为置0;
int sigfillset(sigset_t *set);//填满信号集嘛 调用该函数后,set指向的信号集中将包含linux支持的64种信号,相当于64为都置1;
int sigaddset(sigset_t *set, int signum);//添加信号进去 在set指向的信号集中加入signum信号,相当于将给定信号所对应的位置1;
int sigdelset(sigset_t *set, int signum);//删除信号出去 在set指向的信号集中删除signum信号,相当于将给定信号所对应的位置0;
int sigismember(const sigset_t *set, int signum);//看看是不是已经在里面了 判定信号signum是否在set指向的信号集中,相当于检查给定信号所对应的位是0还是1。
好,看完上面这些处理函数,其实这几个函数真的就是对信号集进行操作而已,而不会对具体信号有什么动作。 别急
7.4 阻塞信号集
阻塞信号集也叫做当前进程的信号屏蔽字。 这里的屏蔽应该理解为阻塞而非忽略
(1)sigprocmask 调用sigprocmask函数可以读取或更改进程的信号屏蔽字。
代码语言:javascript复制#include<signal.h>
int sigprocmask(int how,const sigset_t *set,sigset_t *oldset);
//成功返回0,失败返回-1
参数释义: set:用于更改的信号集 oldset:用于传出原信号集 how:怎么操作set
how的参数选择: SIG_BLOCK:set包含了我们希望添加到当前信号屏蔽字的信号 SIG_UNBLOCK:set包含了我们希望从当前信号屏蔽字移除的信号 SIG_SETMASK:设置当前信号屏蔽字为set所指向的值。
这个要生效的话,至少需要有其中一个信号的驱动(就是哪个倒霉的过来阻塞一下)
(2)sigpending
代码语言:javascript复制#include<signal.h>
int sigpending(sigset_t *set);
//成功返回0,失败返回-1
功能:读取当前进程的未决信号集,通过set参数传出。
到这里差不多可以去弄信号集了
7.5 信号捕捉设定
防止信号意外死亡
代码语言:javascript复制int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
参数释义 signum 捕捉的信号 act 传入的动作 oldact 原动作
我去借鉴了一段代码:捕捉我们给自己定时发送的14号自杀信号:
代码语言:javascript复制#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<sys/time.h>
//定义捕捉函数
void catch_sig(int num){
printf("catch %d sign", num);
}
int main(){
//注册捕捉函数
struct sigaction act;
//说明为你使用的是sigaction结构体中的第一个捕捉函数
act.sa_flags=0;
//那个捕捉函数的函数指针指向我们上面自己写的捕捉函数catch_sig
act.sa_handler=catch_sig;
//清空信号集
sigemptyset(&act.sa_mask);
sigaction(SIGALRM, &act, NULL);
//setitimer 5秒之后每隔3秒来一次信号
struct itimerval myit={{3,0},{5,0}}; //这个后续章节会提到,我现在也不是很清楚
setitimer(ITIMER_REAL, &myit, NULL);//还有这个
while(1){
printf("Who can kill me!n");
sleep(1);
}
return 0;
}
7.6 C标准库信号处理函数
代码语言:javascript复制typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
//signum 要捕捉的信号
//handler 要执行的捕捉函数指针,函数应该声明 void func(int);//函数名可变
7.7 SIGCHLD 信号处理
17号信号
产生条件:
子进程结束时 子进程收到SIGSTOP信号时 子进程处在睡眠状态,收到SIGCONT信号唤醒时
哎,这个有点不好搞,我先把其他方法搞清楚咯 代码也是抄来的,贴这儿了
代码语言:javascript复制#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<sys/wait.h>
void catch_sig(int num){
pid_t pid=waitpid(-1, NULL, WNOHANG);
if(pid>0){
printf("wait child %d okn", pid);
}
}
int main(){
int i=0;
pid_t pid;
for(i=0; i<10; i ){
pid=fork();
if(pid==0){
break;
}
}
if(i==10){
//father
struct sigaction act;
act.sa_flags=0;
sigemptyset(&act.sa_mask);
act.sa_handler=catch_sig;
sigaction(SIGCHLD, &act, NULL);
while(1){
sleep(1);
}
}else if(i<10){
printf("I am %d child, pid=%dn", i, getpid());
sleep(i);
}
return 0;
}