还记得当初开发后端服务的时候,用力敲一下,接口测试通过,程序启动上线。对老板和前端说:我的接口部署好了,你们可以测试一下。然后爽快的收起包,闪身而去,心里默默的说:你们这群没效率的加班狗。前脚还没踏出大门,就听到“xxx,你的接口down了”。我回到座位上查看了一下,果然不能叫。我登录服务器查看,进程没有了。这是怎么回事?隔壁老炮看了我的操作记录,然后在启动命令里加上“nohup&”,就一切ok了。这是我第一次接触到nohup命令,后来才知道这个命令会导致程序忽略HUP信号,保证程序可以正常运行。当终端退出时,它会向关联的进程发送一个SIGHUP信号,进程收到这个信号后会停止运行。所以如果不想让进程被这个信号杀死,可以忽略这个信号。这就是nohup命令的作用。但原理是什么?这里我们来了解两个概念:进程组和会话。进程组进程组是一系列相互关联的进程集合,系统中的每个进程也必然属于某个进程组;每个进程组都会有一个唯一的ID(processgroupid),简称PGID;PGID一般相当于进程组的创建进程的ProcessID,这个进程一般称为进程组组长(processgroupleader),同一个进程组中除进程组组长外的其他进程都是它的子进程流程;进程组的存在,方便了系统对多个相关进程进行一些统一的操作。例如,我们可以同时向同一个进程组中的所有进程发送一个信号量。一个会话(session)是几个进程组的集合。同样,系统中的每个进程组也必须属于某个会话;一个会话最多只能有一个(或没有)控制终端,这个终端是所有进程组中进程的Common。一个会话中只有一个前台进程组,只有其中的进程才能与控制终端进行交互;除前台进程组外的所有进程组都是后台进程组;与进程组长类似,还有一个会话组长(sessionleader的概念)用来表示与控制端建立连接的进程。在与控制终端的会话中,会话领导者也称为控制进程。一般来说,控制进程是登录shell进程(loginshell);执行sleep后台进程sleep50&后,通过ps命令查看进程和shell信息如上图所示:?PPID指父进程id?PID指进程id?PGID指进程组id?SID指的是会话id?TTY指的是会话的控制端设备?COMMAND指的是进程执行的命令?TPGID指的是前台进程组的PGIDSIGHUP信号的触发和默认处理是为了当终端的控制进程结束时,通知同一个会话中的每个作业,然后它们不再与控制终端相关联。系统对SIGHUP信号的默认处理是终止接收到该信号的进程。所以如果程序没有捕捉到信号,那么当接收到信号时,进程就会退出。SIGHUP在以下三种情况下会发送给相应的进程:1.当终端关闭时,信号发送给session第一个进程,并作为job提交的进程(即带&符号提交的进程);2、session第一个进程退出时,向session中的前台进程组中的各个进程发送信号;3.如果父进程退出,则进程组成为孤儿进程组,进程组中的某个进程处于停止状态(收到SIGSTOP或SIGTSTP信号),将发送给进程组中的每一个进程。道理很清楚了,那么除了nohup,还有什么方法可以避免HUP信号导致程序退出呢?答案是c库函数sginal()void(*signal(intsig,void(*func)(int)))(int)其中?sig--在信号处理程序中用作变量的信号代码。文中提到的SIGHUP是信号代码?func--接收到信号后的处理函数。我们调用这个函数来设置一个处理信号的函数,只打印不退出。实验代码如下:#include
