信号的基本概念 信号就是一个软件中断,可以打断进程的执行,让进程处理信号的事件 信号种类: 1-31信号是不可靠信号:信号有可能会丢失(非实时信号)
1.向进程发送非实时信号(该信号没有被挂起),信号响应会嵌套(即正在响应某个函数时,有其它信号发来,进程会先去响应其它信号,结束后再继续原来的任务)。
2.当进程正在响应某个信号时(该信号没有被挂起),即响应函数正在执行的过程中,有相同的n个信号相继发来,进程不会嵌套;
当执行完响应函数后,进程只会执行n个信号中的一个。
3.对非实时信号,挂起的信号不会重复(即有n个相同的信号被挂起,进程只会执行一次)
34-64信号是可靠信号:信号不会丢失(实时信号)
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函数:可以重置当前操作系统对信号的处理方式
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;
}