首页 > 其他分享 >nohup、setsid 与 disown 的不同之处【转】

nohup、setsid 与 disown 的不同之处【转】

时间:2023-07-03 23:34:38浏览次数:38  
标签:SIGHUP setsid nohup 进程 disown id

nohup、setsid 与 disown 都可以用来让需要长期运行的程序在退出终端后继续在后台运行。 然而它们实现这一目的的原理不同,因此使用起来也有一些不同。

 

 

退出终端时发生了什么

 

 

让我们先看看终端退出时发生什么:

 

 

当终端被挂断或伪终端程序被关掉,若终端的 CLOCAL 标志没有被设置,则 SIGHUP 信号会被发送到与该终端相关的控制进程(即会话首进程,通常为 shell)。 而 SIGHUP 的默认行为是终止程序的运行。 当会话首进程终止,也会将 SIGHUP 信号发送给前台进程组中的每一个进程(根据 shell 的具体实现,还可能会把 SIGNHUP 发送给后台进程组)

 

 

nohup、setsid 以及 disown

 

 

那么很自然就会发现,要实现终端退出后进程依然在后台运行,有两种途径:

 

 

  1. 进程收到 SIGHUP 后忽略该信号
  2. 进程根本没有收到 SIGHUP 信号

 

 

nohup

 

 

nohup 的使用方法很简单,只需要在要执行的命令前加上 nohup 就行了。

 

 

nohup commands

 

 

它的原理就是第一种途径。其核心代码为:

 

 

signal (SIGHUP, SIG_IGN);char **cmd = argv + optind;execvp (*cmd, cmd);

 

 

除此之外,它还做了以下动作:

 

 

  • 关闭进程的 stdin,当进程尝试读取输入时,只会得到EOF
  • 重定向进程的 stdout 和stderr 到 nohup.out 中

 

 

由于进程的 stdin,stdout 和 stderr 都脱离了终端,因此让它在前台运行似乎意义不大,一般我们会在后面加上 & 让它在后台运行。

 

 

setsid

 

 

nohup是通过忽略HUP信号来使我们的进程避免中途被中断,而 setsid 可以使我们的进程不属于接受 HUP 号的会话首进程的会话,从而避免受到HUP信号。

 

 

setsid 的使用方法跟 nohup 很类似,只需要在要执行的命令前加上 setsid 即可。

 

 

setsid command

 

 

它的核心代码是 setsid 函数

 

 

pid_t setsid(void);

 

 

调用 setsid 函数的进程若不是一个进程组的组长就会创建一个新会话。具体来说会发生下面3件事情

 

 

  • 该进程会变成新会话的会话首进程(会话首进程即创建该会话的进程),此时新会话中只有该进程这么一个进程
  • 该进程会变成一个新进程组的组长进程,新进程组 ID 就是该进程的 PID
  • 该进程与控制终端的联系被切断。

 

 

若调用 setsid 函数的进程就是一个进程组的组长,则该函数会返回出错。 为了解决这种情况,通常函数需要先fork,然后父进程退出,由子进程执行setsid。 由于子进程继承的是父进程的进程组 ID,而其PID是新分配的ID,因此这两者不可能相等,即子进程不可能是进程组的组长。 这种情况下,由于父进程先于子进程退出,因此子进程的父进程会有init进程接管。 而这就是sid命令的实现原理。

 

 

下面这个实验可以看书 setsid 所做的事情:

 

 

先编译一个测试程序(假设编译后的执行文件为 s.out),源代码如下:

 

 

#include <unistd.h>#include <stdio.h>int main(){  pid_t sid=getsid(0);          /* 会话 id */  pid_t pgrp=getpgrp();         /* 进程组id */  pid_t ppid=getppid();         /* 父进程id */  pid_t pid=getpid();           /* 进程ID */  printf("会话id:%d\n进程组id:%d\n父进程id:%d\n进程id:%d\n",sid,pgrp,ppid,pid);}

 

 

  会话id:17791  进程组id:17791  父进程id:5732  进程id:17791

 

 

在shell下直接执行的输出是:

 

 

[lujun9972@X61 ~]$ ./s.out 会话id:5235进程组id:17095父进程id:5235进程id:17095

 

 

其中5235就是 bash 的进程ID

 

 

而使用 setsid 的执行输出为:

 

 

[lujun9972@X61 ~]$ setsid ./s.out [lujun9972@X61 ~]$ 会话id:17146进程组id:17146父进程id:1进程id:17146

 

 

对比这两个输出,你会发现,setsid新建了一个全新的会话,而且其父进程变成了init京城。

 

 

由于会话和父进程都与shell无关了,因此无论如何shell都无法向该进程发送SIGHUP命令。

 

 

disown

 

 

前面提到的 nohup 和 setsid 都是外部命令,跟具体的shell无关。 即无论shell(同时也是终端相关的控制进程)的具体实现是怎样的都能保证执行的进程不会被SIGHUP挂断。 而且使用他们的一个限制就是必须在执行命令前,事先在命令前加上 nohup 或者 setsid

 

 

是如果我们未加任何处理就已经提交了命令,那就只能使用disown命令了。 然而disown是bash的内置命令,它只能在bash下使用。

 

 

比较常用的disown有以下三种方式

 

 

disown -h $jobspec               #使某个作业忽略HUP信号。disown -ah                       #使所有的作业都忽略HUP信号。disown -rh                       #使正在运行的作业忽略HUP信号。

 

 

disown 命令会将命令从 bash 的 job list 中删除。 这样,当 bash 收到 SIGHUP 信号后,并不会将 SIGHUP 信号发送给该命令。

 

 

然而,使用 disown 并不会切断命令与终端的关联关系,这样当终端被关闭后,若命令尝试从 stdin 中读取或输出到 stdout 中,可能会导致异常退出。

 

 

关于 &

 

 

事实上,在新版本的 bash 上,bash 并不会向后台程序发送 SIGHUP 命令,也就是说任何以 & 结尾运行在后台的进程都不会因为终端退出的SIGHUP信号而退出。

 

 

我们可以做个实验:先准备一个测试文件,代码如下:

 

 

#include <signal.h>#include <stdio.h>#include <unistd.h>void sig_handler(int signo){  if(signo == SIGHUP)    {      printf("RECV SIGHUP\n");    }  else    {      printf("RECV signal %d\n",signo);    }}int main(){  signal(SIGHUP,sig_handler);  sleep(180);}

 

 

编译后(假设编译出来的执行文件是 a.out)在终端中执行:

 

 

a.out >a.txt &

 

 

让程序在后台运行,然后关闭终端,再打开新终端,查看 a.txt 没有发现有内容,用 ps 也能查到 a.out 没有被杀掉,只是它的父进程变成了 init,但若在终端中执行

 

 

a.out >a.txt

 

 

让程序在前台运行,然后关闭终端,再打开新终端,查看 a.txt 则会发现有 RECV SIGHUP 的内容,用 ps 也无法再查到 a.out 了,说明 a.out 也被杀掉了。

标签:SIGHUP,setsid,nohup,进程,disown,id
From: https://www.cnblogs.com/wufj/p/17524458.html

相关文章

  • tmux后台终端程序启动工具-替代nohup后台程序启动工具
    还在用nohup后台执行任务吗?快来用tmux原创 艺说IT 艺说IT 2023-05-2810:09 发表于广东收录于合集#linux3个#linux命令1个文章目录一、前言1.1tmux介绍1.2之前后台运行查看日志的方式二、各系统安装tmux方法2.1CentOS2.2UbuntuAnd......
  • nohup bg命令
    nohupnohup命令可以将程序以忽略挂起信号的形式在后台运行,也就是被运行的程序,输出结果不打印到终端无论是否将nohup命令重定向到终端,nohup命令执行的输出结果都会写入到当前目录的nohup.out文件中如果当前目录的nohup.out文件禁止写入数据,nohup命令的结果会自动输出到$HOME/noh......
  • python nohup 远程运行不宕机方法
    远程运行最怕断电,训练了几个小时的数据说没就没,或者停止运行。用nohup记录代码的输出,还可以不受断电的影响。方法1.用nohup运行一个python文件nohuppython-umain.py>nohup.out2>&1&除了main.py换成自己的文件名,nohup.out也可以改为其他名字,nohup1.out等。其余照搬。不......
  • nohup java -jar 启动java项目
    一、java-jara.jar&直接启动jar文件,在当前会话进程中开启一个子进程来运行程序,这个子进程会随着会话进程的结束而结束。这种情况适合短时间测试用。二、nohupjava-jara.jar&先交代一下名词:hangup(挂断),终端退出时会发送hangup信号来通知其关闭所有子进程。nohup(不挂断......
  • nohup设置springboot项目不挂断地运行错误
    你的linux服务器当前文件夹下之前设置过就需要后面加& 例如 你需要nohupjava-jar***********.jar&命令来将项目挂到后台......
  • Linux 的 nohup 命令的用法
    nohup/root/test.php&1、使用nohup让程序在远程主机后台运行http://www.williamlong.info/archives/482.html......
  • .Linux nohup、&、 2>&1解释
    .Linuxnohup、&、2>&1解释通常起一个jar文件的时候可以直接通过java-jar来启动,比如:A.nohupjava-jar-Dspring.profiles.active=xxx-Dserver.port=xxxxxx.jar>security.out2>&1&B.nohupjava-jargp_doublecontrolle-2.2.6-11-03.jar>>gp_doublecontroll......
  • setsid 使程序脱离终端运行
    直接使用setsidcmd...$ping::1root399698399637014:51pts/4200:00:00ping::1$setsidping::1root3997071014:52?00:00:00ping::1注意看,现在它已经没有隶属任何进程组(父进程是init)和隶属的会话(没有控制终端pts/x),如果此刻......
  • Linux nohup 命令
    这个命令太重要了,是很多服务启动必须要用到的。nohupcontrol.sh>/dev/null2>&1&Linuxnohup命令nohup英文全称nohangup(不挂起),用于在系统后台不挂断地运行命令,退出终端不会影响程序的运行。nohup命令,在默认情况下(非重定向时),会输出一个名叫nohup.out的文件到当前......
  • linux下利用nohup后台运行jar文件包程序
    Linux运行jar包命令如下:方式一: 1.java-jarXXX.jar特点:当前ssh窗口被锁定,可按CTRL+C打断程序运行,或直接关闭窗口,程序退出那如何让窗口不锁定?方式二 1.java-jarXXX.jar&&代表在后台运行。特定:当前ssh窗口不被锁定,但是当窗口关闭时,程序中止运行。继续改......