信号的基本概念
信号就是一个软件中断,能够打断进程的执行,让进程处理信号的事件
信号种类:
1-31信号是不可靠信号:信号有可能会丢失(非实时信号)
编程
1.向进程发送非实时信号(该信号没有被挂起),信号响应会嵌套(即正在响应某个函数时,有其它信号发来,进程会先去响应其它信号,结束后再继续原来的任务)。 2.当进程正在响应某个信号时(该信号没有被挂起),即响应函数正在执行的过程当中,有相同的n个信号相继发来,进程不会嵌套; 当执行完响应函数后,进程只会执行n个信号中的一个。 3.对非实时信号,挂起的信号不会重复(即有n个相同的信号被挂起,进程只会执行一次)
34-64信号是可靠信号:信号不会丢失(实时信号)ide
1.向进程发送实时信号(该信号没有被挂起),信号响应会嵌套。 2.当进程正在响应某个信号时(该信号没有被挂起),即响应函数正在执行的过程当中,有相同的n个信号相继发来,进程不会嵌套; 当执行完响应函数后,进程会继续执行函数n次。 3.对实时信号,挂起的信号能够重复(即有n个相同的信号被挂起,进程会执行n次)
若是进程的挂起信号中含有实时和非实时信号,那么进程优先响应实时信号并会从大到小依次响应,而非实时信号没有固定的次序,甚至某个非实时信号会被丢失(这可说明为何非实时信号被叫作不可靠信号)。
信号产生方式:
1.硬件产生:ctrl+c(SIGINT),ctrl+z(SIGTSTP),ctrl+|(SEGOUIT)
2.软件产生:kill -信号号码+进程号
eg:kill -9 12345
kill函数:kill(信号号, SIGINT);//给给定信号号的进程发送SIGINT信号
abort函数:void abort();给当前进程发送SIGABRT信号
raise函数:int raise(int sig);给当前进程发送sig信号
alarm函数:unsigned int alarm(unsigned int seconds);
seconds秒以后,给调用进程发送SIGALRM信号
seconds若为0,则表示取消上一个定时器
返回值:上一个定时器的剩余时间
函数
alarm(3);//定时3秒 sleep(1);//表示alarm会响应2秒 alarm(0);//取消3秒定时器
core dumped:核心转储文件命名格式:core.pid
ulimit -a 查看
ulimit -c 设置core文件最大大小,单位为kb ulimit -c 1024
调试方法:gdb ./main->core.file core.pid ->bt
信号的生命周期
信号在进程当中的注册
非可靠信号(1~31):
若是待注册的信号,在pending位图当中已经存在了,则再也不去添加当前信号(意味着不增长sigqueue节点)
若是待注册的信号,在pending位图中不存在,将pending位图当中的对应的bit位置位1,而后添加sigqueue节点
可靠信号(34~64):
若是待注册的信号,在pending位图当中存在(意味着对应的bit位为1),另外增长sigqueue节点(意味着这个信号也会被处理)
若是待注册的信号,在pending位图当中不存在,则更改pending位图中对应的bit位,而且增长sigqueue节点
信号在进程当中的注销
1.非可靠信号
将pending位图当中的对应的bit位置为0,而且将sigqueue节点删除
2.可靠信号
若是注销的信号,存在的sigqueue节点只有1个,则将pending位图当中的对应的bit位置为0,而且将sigqueue节点删除
若是注销的信号,存在sigqueue节点有多个,不能将pending位图当中对应的bit位置为0,而是删除一个sigqueue节点
操作系统
信号的处理
默认处理方式---SIG_DFL
忽略处理方式---SIG_IGN
自定义处理方式
调试
signal函数:能够重置当前操做系统对信号的处理方式code
typedef void (* sighandler_t)(int);
sighandler_t signal(int signum,sighandler_t handler);
生命周期
#include <stdio.h> #include <unistd.h> #include <signal.h> void sigbackfunc(int sig) { printf("sig : [%d]\n", sig); signal(2, SIG_DFL);//遇到2号信号以后,忽略处理 } int main() { signal(SIGINT, sigbackfunc);//收到2号信号以后,自定义处理(转到sigbackfunc函数) while(1) { printf("hello~\n"); sleep(1); } return 0; }
sigaction函数进程
int sigaction(int signum,const struct sigaction act,struct sigaction oldact);
act:表示将当前信号修改为一种处理方式,让操做系统接收到这个信号的时候,调用哪个函数处理
oldact:表示以前操做系统对收到该信号的时候 的处理方式
事件
#include <stdio.h> #include <signal.h> #include <unistd.h> void sigbackfunc(int sig) { printf("%d\n", sig); } int main() { struct sigaction newact; struct sigaction oldact; newact.sa_handler = sigbackfunc; newact.sa_flags = 0; sigemptyset(&newact.sa_mask); sigaction(2, &newact, &oldact); while(1) { printf("hello\n"); sleep(1); } return 0; }
信号捕捉流程资源
信号阻塞
信号阻塞不是说信号不能被注册,而是说,从操做系统在判断pending位图是发现接受某个信号了,去查找block位图对应的bit位
若是block对应的位为1,则不处理该信号,sigqueue节点仍是在的
若是block对应的位置为0,则处理该信号
int sigprocmask(int how,const sigset_t set,sigset_t oldset);
how:SIG_BLOCK-->设置某个信号为阻塞状态,block(new)=block(old) | set
SIG_UNBLOCK-->设置某个信号为非阻塞状态,block(new)=block & (~set)
SIG_SETMASK-->设置新位图block=set
block:0000 0000 set : 1111 1111 (阻塞信号) block(new)=block(old) | set 1111 1111 (非阻塞信号)block(new)=block & (~set) 1111 1111 & (0000 0000)-->0000 0000
注意
9号,19号信号是不能设置为阻塞的
#include <stdio.h> #include <unistd.h> #include <signal.h> void sigcallback(int sig) { printf("sig : [%d]\n", sig); } int main() { signal(2, sigcallback); signal(40, sigcallback); //block位图设置一下,也就是阻塞某些信号 //int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); sigset_t set, oldset; sigemptyset(&set); sigemptyset(&oldset); //给set位图编程全1 //int sigfillset(sigset_t *set); sigfillset(&set); sigprocmask(SIG_BLOCK, &set, &oldset); getchar(); sigprocmask(SIG_UNBLOCK, &set, NULL); while(1) { ; } return 0; }
竞态条件
程序的不一样的执行流,执行顺序的不一样,会致使程序结果的不一样,这种咱们称之为竞态条件
重入:不一样的执行流能够访问一样的资源(代码) 可重入:不一样的执行流能够访问一样的资源,不会对程序的结果产生影响 不可重入:不一样的执行流能够访问一样的资源,可是对程序的结果产生影响 不可重入场景:全局变量,malloc和free ,绝大多数的库函数
SIGCHLD--17号信号
SIGCHLD信号的默认行为是不处理,咱们能够更改掉SIGCHLD信号的默认处理函数,让收到该信号的时候调用自定义的函数去完成进程等待,从而父进程就能够完成本身的逻辑,而不用调用wait进行阻塞了,意味着了,咱们能够在回调函数中调用wait
#include <stdio.h> #include <signal.h> #include <unistd.h> #include <sys/wait.h> #include <stdlib.h> void sigcallback(int sig) { printf("sig : %d\n", sig); wait(NULL); } int main() { signal(SIGCHLD, sigcallback); pid_t pid = fork(); if(pid < 0) { return pid; } else if(pid == 0) { //child printf("i am child\n"); sleep(3); exit(1); } else { //wait while(1) { printf("我不听~~~\n"); sleep(1); } } return 0; }