bash和终端

1
2
3
ps -ef | grep bash

UID PID PPID C STIME TTY TIME CMD

pts(虚拟终端),每连接一个虚拟终端到ubantu操作系统就会新出现一个bash进程(shell【壳】),bash运行起来就是那个黑窗口,bash用来解释用户输入的各个命令比如ls,ps等

bash=shell=命令解释器,,,bash是一个可执行文件

image-20220123143035840

用xshell创建一个新连接后可以观察到多了一个bash进程

image-20220123143059291

bash是一个可执行文件,每打开一个终端就会多出一个bash进程。

终端和进程

进程组和会话

每个进程还属于一个进程组:一个或者多个进程的集合,每个进程组有一个唯一的进程组ID,可以调用系统 函数来创建进程组、加入进程组
“会话”(session):是一个或者多个进程组的集合.

image-20220123165758700

一般,只要不进行特殊的系统函数调用,一个bash(shell)上边运行的所有程序都属于一个会话,而这个会话有一个session leader;

那么这个bash(shell)通常就是session leader; 你可以调用系统功函数创建新的session。

ps -eo

image-20220123153121864

a)如果我 xshell终端要断开的话,系统就会发送SIGHUP信号(终端断开信号),给session leader,也就是这个bash进程
b)bash进程 收到 SIGHUP信号后,bash会把这个信号发送给session里边的所有进程,收到这个SIGHUP信号的进程的缺省动作就是退出;

strace跟踪

关闭运行nginx的终端后bash如图所示,

image-20220123160905196

如下图所示,kill(-5871, SIGHUP) :发送信号SIGHUP给这个 -5871的绝对值(nginx进程ID)所在的进程组;所以nginx进程就收到了SIGHUP信号
综合来讲,这个bash先发送SIGHUP给同一个session里边的所有进程;
然后再发送SIGHUP给自己;

image-20220123160922737

孤儿进程

父进程运行结束,但子进程还在运行(未运行结束)的子进程就称为孤儿进程(Orphan Process)。孤儿进程最终会被 init 进程(进程号为 1 )所收养,并由 init 进程对它们完成状态收集工作。

孤儿进程是没有父进程的进程,为避免孤儿进程退出时无法释放所占用的资源而变为僵尸进程,进程号为 1 的 init 进程将会接受这些孤儿进程,这一过程也被称为“收养”。init 进程就好像是一个孤儿院,专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候,内核就把孤 儿进程的父进程设置为 init ,而 init 进程会循环地 wait() 它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init 进程就会代表党和政府出面处理它的一切善后工作。因此孤儿进程并不会有什么危害。

终端关闭不退出进程

方法一:代码里设置忽略对应signal的逻辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <unistd.h>

#include <signal.h>

int main()
{
//系统函数,设置某个信号来的时候处理程序(用哪个函数处理)
signal(SIGHUP,SIG_IGN);//SIG_IGN标志:忽略这个信号,操作系统不要杀死我

while(1){
printf("hello world!\n");
sleep(1);
}
printf("程序结束,退出!\n");
return 0;
}

image-20220123161146726

直接关闭运行nginx的那个终端之后,ngnix变成了孤儿进程。

方法二:代码里借助setsid函数并借助子进程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>
#include <unistd.h>
int main()
{
pid_t pid = fork();
if(pid < 0){
printf("fork()进程出错!\n");
}
else if(pid == 0){//子进程
printf("子进程开始执行\n");
setsid();//新建立一个新的不同sessionId,但是进程组组长不会调用该函数成功

while(1){
printf("hello world!\n");
sleep(1);
}
}
else if(pid > 0){
while(1){
printf("hello world!\n");
sleep(1);
}
}

printf("程序结束,退出!\n");
return 0;
}

image-20220123163106095

方法三:命令行使用setsid
1
setsid ./nginx

image-20220123163827242

方法四:命令行使用nohup
1
nohup ./nginx

image-20220123164916732

nohup(no hang up不要挂断),用该命令启动的进程跟上边忽略掉SIGHUP信号,道理相同。该命令会把屏幕输出重新定位到当前目录的nohup.out而不是直接打印到终端

后台运行

1
./nginx &

后台运行当前程序,可以输入命令并且解释运行但是ctrl+’c’无法停止当前程序,只能等程序运行完成。fg切换到前台后才可以用ctrl+’c’停止当前程序。