wordpress全站公告,wordpress激活码,自豪地采用wordpress 怎么去掉,百度搜索引擎的特点现象 经常在linux下开发的人应该都有这样的经验#xff0c;就是在终端上启动的程序#xff0c;在关闭终端时#xff0c;这个程序的进程也被一起关闭了。看下面这个程序#xff0c;为了使进程永远运行#xff0c;在输出helloworld后#xff0c;循环调用sleep#xff1a; … 现象 经常在linux下开发的人应该都有这样的经验就是在终端上启动的程序在关闭终端时这个程序的进程也被一起关闭了。看下面这个程序为了使进程永远运行在输出helloworld后循环调用sleep 直接关闭这个终端在另一个终端上查找该进程已经找不到了 这个行为看起来似乎是理所当然的也符合人的第一感觉”在终端上启动的程序是属于终端的所以当关闭终端时这个终端里的一包裹进程都一起被解决掉了”。但这种说法是不能使一个会思考且充满好奇心的人信服的。 下面我们就从linux进程管理的细节来剖析其根本原因。 终端进程 linux系统是基于进程的几乎每个命令都可以在相应的目录下找到它们的程序执行一个命令相当于启动一个或多个程序终端也不例外在我centos下面终端对应一个bash程序(不同操作系统终端的bash程序可能不一样)它位于/usr/bin/下面 每当打开一个终端都会启动一个bash进程我这里启动了两个终端可以看到有两个bash进程 终端进程与启动进程的关系 linux系统里面所有的进程的关系可以看做一个树形结构系统持续运行进程的不断启动就是不断fork的过程fork是linux系统api作用是复制自己来生成子进程从系统启动、初始化、登录终端、到执行命令都是生成子进程的过程: init进程是所有进程的祖先它的pid进程id为1ppid父进程id也为1因为它没有父进程系统内的其他进程都是由它或者它的子进程fork而来。 我们在linux上作业的终端对应了一个bash进程在其上运行的命令和程序都是bash的子进程或由bash的子进程衍生。 用hw程序验证一下可以看到hw进程的父进程正好是bash进程 但这并不能解释为什么终端关闭了在上面运行的程序也跟着退出因为在linux下进程之间的关系并不像线程那样当主线程退出时子线程一起被强制退出。进程之间没有主次的区别但有父子关系而父子进程的运行是相对独立的一方的退出不会导致另一方退出。 进程session-揭开真相 在linux下一个session是由一组进程组构成的每个进程组又由多个进程构成。 在一个bash上运行的程序都归属于一个session除非特别处理而这个bash就是这个session的leader。每个session又可以关联一个控制终端Controlling Terminal。 图片
hw进程的ppid5933说明父进程为第一个bash这个bash的父进程为gnome-ternimal进程gnome-ternimal是centos可视化界面的终端管理进程每打开一个终端它都会启动一个bash进程而用户的命令也是直接由bash进程执行的。hw程序和第一个bash同属于一个sessionsid5933这个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 tracesignal -p 6367 跟踪bash进程命令意为跟踪pid为5933的进程上与signal有关的系统调用: strace -e tracesignal -p 5933 关闭启动hw程序的终端观察strace输出. hwd的strace如下si_pid5933说明是5933这个进程发了SIGHUP给它也就是bash进程 bash的strace略微复杂 kill(4294960929, SIGHUP) kill第一个参数是32位有符号整数转换成int就是-6367当参数为负时表示发送给这个数绝对值的进程组即pgrp6367的所有进程在上面的图片中可以看到hw进程正好属于该进程组。 kill(5933, SIGHUP) 5933是自己的pidbash在第一次收到SIGHUP时先把信号发给session内其他进程然后再次发送SIGHUP命令给自己将自己杀死后面的si_pid5933也证实了这一点。 如何让终端关闭时进程不退出 根据上面的结论要使终端关闭时进程不退出有以下几种情况
用户进程拦截SIGHUP信号。用户进程和bash进程不在一个session。 下面依次验证这两种情况 拦截SIGHUP 修改hw程序忽略SIGHUP信号
signal(SIGHUP, SIG_IGN);
12 执行hw程序并查看进程可以看到hw进程和父进程bash 关闭终端在另一个终端查看进程 bash进程已经退出但hw进程还在符合预期而且hw进程的ppid变成了1说明hw在父进程bash退出后变成孤儿进程被init进程收养。 新建sessionsetsid 为了使用户进程和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);}
}
1234567891011121314151617 调用setsid前先fork因为若不forkhw作为进程组的leader是不允许重建session的原因留给读者自己思考。 编译并执行hw查看进程 可以看到相比之前有几个不同的地方
程序启动完返回终端hw切换到后台运行。hw进程的父进程不再是bash而是init进程。hw没有关联的终端设备pts/2。 关闭终端看到bash已经消失但对hw进程没有任何影响 更简单的方法 setsid命令用setsid来启动程序这样就不用修改任何代码也可以做到使启动的进程在新的session中并且终端关闭时进程不退出。 setsid ./hw nohup命令被nohup启动的程序会忽略SIGHUP信号。 nohup ./hw 其他 命令行中的作用
./hw
12 的作用是使程序在后台运行输入fg命令又可以使程序切换到前台。虽然在后台运行但并不能保证进程在终端关闭时不退出。 总结 简而言之终端在关闭时会发送SIGHUP给对应的bash进程bash进程收到这个信号后首先将它发给session下面的进程如果你的程序没有对SIGHUP信号做特殊处理那么进程就会随着终端关闭而退出。