Nodejs 进程信号
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Nodejs 进程信号相关的知识,希望对你有一定的参考价值。
参考技术A 首先我们来看一个简单的master/worker的例子worker程序
首先无论在子进程还是父进程都可以接收linux的信号 SIGINT,SIGTERM,SIGHUP 等。
只要是程序能够监听到的退出信号。我们都可以统一通过监听 exit 来处理程序
进程信号
信号的基本概念
信号就是一个软件中断,可以打断进程的执行,让进程处理信号的事件
信号种类:
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]
", sig);
signal(2, SIG_DFL);//遇到2号信号之后,忽略处理
}
int main()
{
signal(SIGINT, sigbackfunc);//收到2号信号之后,自定义处理(转到sigbackfunc函数)
while(1)
{
printf("hello~
");
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
", 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
");
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]
", 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
", 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
");
sleep(3);
exit(1);
}
else
{
//wait
while(1)
{
printf("我不听~~~
");
sleep(1);
}
}
return 0;
}
以上是关于Nodejs 进程信号的主要内容,如果未能解决你的问题,请参考以下文章