linux终端关闭时为什么会导致在其上启动的进程退出?
现象
经常在linux下开发的人应该都有这样的经验,就是在终端上启动的程序,在关闭终端时,这个程序的进程也被一起关闭了。看下面这个程序,为了使进程永远运行,在输出helloworld后,循环调用sleep:
直接关闭这个终端,在另一个终端上查找该进程,已经找不到了:
这个行为看起来似乎是理所当然的,也符合人的第一感觉:”在终端上启动的程序是属于终端的,所以当关闭终端时,这个终端里的一包裹进程都一起被解决掉了”。但这种说法是不能使一个会思考且充满好奇心的人信服的。
下面我们就从linux进程管理的细节来剖析其根本原因。
终端进程
linux系统是基于进程的,几乎每个命令都可以在相应的目录下找到它们的程序,执行一个命令相当于启动一个或多个程序,终端也不例外,在我centos下面终端对应一个bash程序(不同操作系统终端的bash程序可能不一样),它位于/usr/bin/下面:
每当打开一个终端都会启动一个bash进程,我这里启动了两个终端,可以看到有两个bash进程:
终端进程与启动进程的关系
linux系统里面所有的进程的关系可以看做一个树形结构,系统持续运行,进程的不断启动就是不断fork的过程(fork是linux系统api,作用是复制自己来生成子进程),从系统启动、初始化、登录终端、到执行命令都是生成子进程的过程:
init进程是所有进程的祖先,它的pid(进程id)为1,ppid(父进程id)也为1,因为它没有父进程,系统内的其他进程都是由它或者它的子进程fork而来。
我们在linux上作业的终端对应了一个bash进程,在其上运行的命令和程序都是bash的子进程,或由bash的子进程衍生。
用hw程序验证一下,可以看到hw进程的父进程正好是bash进程:
但这并不能解释为什么终端关闭了在上面运行的程序也跟着退出,因为在linux下,进程之间的关系并不像线程那样,当主线程退出时,子线程一起被强制退出。进程之间没有主次的区别,但有父子关系,而父子进程的运行是相对独立的,一方的退出不会导致另一方退出。
进程session-揭开真相
在linux下,一个session是由一组进程组构成的,每个进程组又由多个进程构成。
在一个bash上运行的程序都归属于一个session(除非特别处理),而这个bash就是这个session的leader。每个session又可以关联一个控制终端(Controlling Terminal)。
图片:
- hw进程的ppid=5933,说明父进程为第一个bash,这个bash的父进程为gnome-ternimal进程,gnome-ternimal是centos可视化界面的终端管理进程,每打开一个终端,它都会启动一个bash进程,而用户的命令也是直接由bash进程执行的。
- hw程序和第一个bash同属于一个session(sid=5933),这个sid等于bash的pid,所以第一个bash是这个session的leader。
- 图片中还显示了bash和hw进程拥有共同的终端设备pts/2,它是一种字符设备,不同于上面提到的gnome-ternimal进程。
- 当控制终端(对应gnome-ternimal)检测到终端设备断(对应pts/2)开连接时,会通知设备的控制进程,即发送SIGHUP信号给session leader(对应bash进程)。
- bash进程在收到SIGHUP后,将信号发给session下的所有进程,导致用户启动的进程退出。
下面通过strace命令来验证以上结论:
跟踪hw进程(命令意为跟踪pid为6367的进程上与signal有关的系统调用):
strace -e trace=signal -p 6367
跟踪bash进程(命令意为跟踪pid为5933的进程上与signal有关的系统调用):
strace -e trace=signal -p 5933
关闭启动hw程序的终端,观察strace输出.
hwd的strace如下,si_pid=5933说明是5933这个进程发了SIGHUP给它,也就是bash进程:
bash的strace略微复杂:
kill(4294960929, SIGHUP)
kill第一个参数是32位有符号整数,转换成int就是-6367,当参数为负时表示发送给这个数绝对值的进程组,即pgrp=6367的所有进程,在上面的图片中可以看到hw进程正好属于该进程组。
kill(5933, SIGHUP)
5933是自己的pid,bash在第一次收到SIGHUP时先把信号发给session内其他进程,然后再次发送SIGHUP命令给自己,将自己杀死,后面的si_pid=5933也证实了这一点。
如何让终端关闭时进程不退出
根据上面的结论,要使终端关闭时进程不退出,有以下几种情况:
- 用户进程拦截SIGHUP信号。
- 用户进程和bash进程不在一个session。
下面依次验证这两种情况
拦截SIGHUP
修改hw程序,忽略SIGHUP信号:
signal(SIGHUP, SIG_IGN);
- 1
- 2
执行hw程序,并查看进程,可以看到hw进程和父进程bash:
关闭终端,在另一个终端查看进程:
bash进程已经退出,但hw进程还在,符合预期!!而且hw进程的ppid变成了1,说明hw在父进程bash退出后变成孤儿进程被init进程收养。
新建session&setsid
为了使用户进程和bash不在同一个session,需要调用setsid方法,该方法的作用是新建一个新的session,并使自己成为leader。
// 先fork
int pid = fork();
if(pid > 0){// 父进程, 直接退出return 1;
}else if(pid == 0){// 子进程// 创建新的sessionsetsid();//printf("Hello World!\n");printf("sleeping...\n");while(1){sleep(1);}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
调用setsid前先fork,因为若不fork,hw作为进程组的leader,是不允许重建session的,原因留给读者自己思考。
编译并执行hw,查看进程:
可以看到,相比之前,有几个不同的地方:
- 程序启动完,返回终端,hw切换到后台运行。
- hw进程的父进程不再是bash,而是init进程。
- hw没有关联的终端设备(pts/2)。
关闭终端,看到bash已经消失,但对hw进程没有任何影响:
更简单的方法
setsid命令,用setsid来启动程序,这样就不用修改任何代码也可以做到使启动的进程在新的session中,并且终端关闭时,进程不退出。
setsid ./hw
nohup命令,被nohup启动的程序会忽略SIGHUP信号。
nohup ./hw
其他
命令行中&的作用:
./hw &
- 1
- 2
&的作用是使程序在后台运行,输入fg命令又可以使程序切换到前台。虽然在后台运行,但并不能保证进程在终端关闭时不退出。
总结
简而言之,终端在关闭时会发送SIGHUP给对应的bash进程,bash进程收到这个信号后首先将它发给session下面的进程,如果你的程序没有对SIGHUP信号做特殊处理,那么进程就会随着终端关闭而退出。
linux终端关闭时为什么会导致在其上启动的进程退出?相关推荐
- java 不退出_Java项目不挂断运行,即当账户退出或终端关闭时,程序仍然运行,并附上执行脚本...
把打包好的jar包上传服务器以后,直接运行java -jar+文件名 命令即可以完成启动. 若需要在公网上如何不挂断开启程序,可以使用nohup java -jar +文件名 &命令,其中no ...
- LINUX终端登录时提示 Login incorrect
1. LINUX终端登录时提示 Login incorrect 问题:(1)通过 VMware虚拟机软件安装的 CentOS 操作系统,在通过选择图形界面窗口 GNOME(建议选择经典模式) 进 ...
- linux启动一个进程吗,你知道,当你在 Linux 上启动一个进程时会发生什么嘛?
原标题:你知道,当你在 Linux 上启动一个进程时会发生什么嘛? 本文是关于 fork 和 exec 是如何在 Unix 上工作的.你或许已经知道,也有人还不知道.几年前当我了解到这些时,我惊叹不已 ...
- linux如何启动一个进程而不阻塞,当你在 Linux 上启动一个进程时会发生什么? | Linux 中国...
原标题:当你在 Linux 上启动一个进程时会发生什么? | Linux 中国 本文是关于 fork 和 exec 是如何在 Unix 上工作的.你或许已经知道,也有人还不知道.几年前当我了解到这些时 ...
- linux启动一个进程吗,当你在Linux上启动一个进程时会发生什么?
本文是关于 fork 和 exec 是如何在 Unix 上工作的.你或许已经知道,也有人还不知道.几年前当我了解到这些时,我惊叹不已. 我们要做的是启动一个进程.我们已经在博客上讨论了很多关于系统调用 ...
- linux终端关闭xmanager,xmanager功能和设置
一下总结这些资料也是根据网上更改过来的,网上有很多人给的是错的或是版本不同的,浪费了我很长时间,总结了这些希望能对你有用,本人试过3个版本的系统都通过. Xmanager是跨平台的一个软件,win远程 ...
- linux终端关闭xmanager,xmanager之linux 解决方法
xmanger防火墙[@more@] 转载]xManager与防火墙的问题解决过程文章作者:天天 最近部门进了一台V880R,用CDE,放在DMZ区,这样的话,如果要用X-manager访问的话就要涉 ...
- Linux终端关闭屏幕显示,使用命令行关闭监视器
问题描述 我正在我的笔记本电脑上运行Ubuntu Server.屏幕没有理由打开.我一直在尝试使用此命令关闭屏幕: sleep 1 && xset dpms force off 问题是 ...
- linux终端关闭xmanager,关于使用Xmanager进行对linux远程桌面控制
通过xmanager管理linux(本文用red hat linux)需要在linux下做相应的设置以启动服务.主要分为七步来进行设置. 配置linux. 1 打开 /etc/inittab文件,将 ...
最新文章
- fedora18 fedora17安装显卡驱动和网卡驱动
- 浏览器设置了打开会显示特定网页为什么还是显示2345_Edge没能取代Chrome成为我的主力浏览器...
- jQuery复制节点
- LeetCode 2110. 股票平滑下跌阶段的数目(滑动窗口)
- Java基础入门笔记-构造方法的继承
- (十一)Hibernate 高级配置
- 雷军:电视机越大才越舒服!
- C++的掐拷贝、深拷贝【面向对象程序设计细节】
- Portlet MVC框架
- 开发板识别不了SD/TF卡
- 深信服 SANGFOR 设备密码恢复和配置备份恢复
- Liunx安装Ubuntu系统
- 领域驱动设计(DDD)之领域专家
- 1000w+条中国大陆企业工商注册信息数据集
- 重置ubuntu密码
- mysql sysvar int_MySQL:如何编写daemon plugin
- 马化腾是学计算机的吗,马化腾大学实际上是病毒编写者,经常编写感染计算机的程序...
- python里load什么意思_【python】json中load和loads区别
- U启动后计算机能看到原系统文件吗,u启动一键急救系统使用
- Java 开发工具包 Java SE Development Kit 8/11LTS/15
热门文章
- linux里的进程简介
- html5录像功能限制时间,HTML5拍照和摄像机功能实战详解
- ft服务器设置传输协议,ft服务器设置成主动模式
- fst java_java快速序列化库FST
- mysql binlog redo_mysql的binlog与redo log
- 无法访问netflix服务_Choerodon 的微服务之路(三):服务注册与发现
- 西安4年java多少时间_西安学习java一般要多久
- java底层 文件操作_JAVA的文件操作【转】
- 查看环境列表_Xfce 4.14桌面环境正式发布,想要图形界面又想节省内存?就它了...
- 算法—递归实现 C(m,n)