Linux终端与进程的关系 ( 1 ) -【Linux通信架构系列】

news2024/12/23 23:05:07

系列文章目录

C++技能系列
Linux通信架构系列
C++高性能优化编程系列
深入理解软件架构设计系列
高级C++并发线程编程

期待你的关注哦!!!
在这里插入图片描述

现在的一切都是为将来的梦想编织翅膀,让梦想在现实中展翅高飞。
Now everything is for the future of dream weaving wings, let the dream fly in reality.

Linux终端与进程的关系

  • 系列文章目录
  • 一、Linux 进程关系
    • 1.1 Linux 进程相关概念「进程关系、进程组、进程会话」
  • 二、终端与进程的关系
    • 2.1 终端与bash进程
    • 2.2 终端上的开启进程
    • 2.3 为什么终端一退,进程就退出了
    • 2.4 strace 工具的使用
    • 2.5 终端关闭时如何让进程不退出
      • 2.5.1 nginx进程拦截SIGHUP信号
      • 2.5.2 nginx进程和bash进程在不同的session中(不同的session ID)
      • 2.5.3 直接使用setsid命令
      • 2.5.4 直接使用 nohup命令(no hang up 不挂断)
    • 2.6 后台执行(运行)的简单理解

一、Linux 进程关系

1.1 Linux 进程相关概念「进程关系、进程组、进程会话」

进程之间是一种属性的结构关系,如图:

在这里插入图片描述

图1.1 进程关系图

最上面的init进程是“老祖宗”进程(操作系统启动时内核自己创建出来的,具有超级用户特权)。init进程的进程ID(PID)是1,系统内的其他进程应该都是由它或者它的子进程fork(创建)出来的。

终端输入ps -ef命令查看结果:
在这里插入图片描述

图1.2 PID为1的进程就是init进程

进程关系进一步分析:

进程有进程ID(PID),有父进程ID(PPID)。还要知道一点:每个进程还可以属于一个进程组(分成组方便管理,例如可以给整个组发送一条信息等)。 “进程组”代表一个或多个进程的集合 。每个进程组有一个唯一的进程组ID,一个进程组中的各个进程可以独立接收来自终端的各种信号。可以通过调用系统函数创建进程组、加入进程组等。

了解进程组概念之后,我们引入一个新的概念: “会话”(Sessiond)是一个或多个进程组的集合。

在这里插入图片描述

图1.3 一个session包含一个或多个进程组,一个进程组包含一个或多个进程

一般来讲,如果不调用特殊的系统函数进行特殊处理,1个bash(shell)上运行的所有程序将属于一个会话(session),而这个会话有1个会话首进程(session leader,就是创建该会话的进程),这个shell(bash)通常就是session leader。另外,还可以调用函数创建新的session。

二、终端与进程的关系

2.1 终端与bash进程

启动Ubuntu Linux虚拟机,用Xshell链接虚拟机,输入如下命令:
ps -ef | grep bash

进程ID为 19501就是bash进程(既Xshell 链接到Ubuntu Linux虚拟机产生的进程),如图2.1所示:
在这里插入图片描述

图2.1.1 查找包含bash字样的进程(1个)

再建一个Xshell链接虚拟机会话窗口,输入**ps -ef | grep bash**命令,如图2.12所示:
在这里插入图片描述

图2.1.2 查找包含bash字样的进程(2个)

可以看出,此时有2个bash进程(因为有两个Xshell连入了Ubuntu Linux虚拟机),进程ID分别为 19501和3253,我们可以看到图中pts/0和pts/1,pts就是虚拟终端

每个虚拟机终端链接到Ubuntu Linux虚拟机上,都会打开一个bash进程(也叫shell - 壳)。向其中输入各种命令的黑窗口就是bash,用于解释用户输入的命令。在Xshell中输入一条命令并按回车键后,命令就会被bash进程解释并执行(bash就是shell,也就是命令行解释器是一个可执行程序)。

可以使用whereis命令查找bash可执行程序的位置,如图2.13所示:
whereis bash
在这里插入图片描述

图2.1.3 使用whereis命令查找bash可执行程序的位置

2.2 终端上的开启进程

在VSCode自己编写nginx.c代码,内容如下:

#include <stdio.h>
#include <unistd.h>
int main(int argc, char *const *argv)
{
        printf("hello nginx\n");
        for(;;)
        {
                sleep(1);
                printf("休息1s\n");
        }
        printf("程序退出!再见!\n");
}

运行./nginx, 并在另一个终端窗口输入:
ps -la
-l代表比较长的输出显示格式;-a代表显示终端上的所有进程(包括其他终端的进程)

在这里插入图片描述

图2.2.1 执行ps -la的结果
这是一个无限循环的程序,会不断重复输出“休息1秒”,可以按`Ctrl + C`组合键停止。

2.3 为什么终端一退,进程就退出了

现在,把自己写的这个nginx可执行程序在某个终端再次启动,然后再打开两个Xshell终端,保持3个终端在运行的状态。

在终端输入如下命令:
ps -eo pid,ppid,sid,tty,pgrp,comm | grep -E 'bash|PID|nginx'

e代表所有进程;o代表自己指定显示哪些列(sid表示session id, tty表示终端, pgrp表示进程组, comm表示执行的命令);grep命令中,-E代表要开启扩展正则表达式功能,用于配合后面的bash|PID|nginx以显示特定名字的进程;| 代表或者关系;bash|PID|nginx代表bash、PID、nginx这几个字符串中的某个出现就会被显示。
在这里插入图片描述

图2.3.1 用ps命令显示指定名字的进程

观察图2.3.1:

(1)nginx进程的PPID是3253,而3253是某个bash的PID,说明nginx是某个bash的子进程。

(2)nginx进程的SID是3253,而3253是这个bash的PID,同时还是这个bash的SID,也就是说这个bash的SID等于PID,这就意味着这个bash是整个会话(session)的会话首进程(session leader)。

nginx进程的PID和PGRP都是14942,说明nginx自成一组。

(3)PID=3253的bash进程和nginx进程,它们的TT(tty)都是pts/0(编号为0的终端)。

(4)bash进程收到SIGHUP信号后,就会把这个信号发送给session 里面的所有进程,收到这个SIGHUP信号的进程默认动作就是退出。

分析到这里应该就明白了 - 为什么终端一退,进程就退出了。

2.4 strace 工具的使用

strace是Linux中的调试分析诊断工具,功能强大,可以用于跟踪程序执行时进程的系统调用(system call)和所接收到的信号。现在来看strace工具如何使用。

(1)执行如下命令:sudo strace -e trace=signal -p 23099

这条命令用于跟踪PID为23099的进程(nginx进程)上与信号(signal)有关的系统调用。也就是说,这条命令把trace工具附着到进程23099上了。如图所示:
在这里插入图片描述

图2.4.1 将strace 工具附着到进程23099(nginx)进程上

(2)现在打开第三个终端窗口,再使用strace附着一下nginx进程PPID为3253的父进程(bash)
sudo strace -e trace=signal -p 3253
在这里插入图片描述

图2.4.2 将strace 工具附着到3253进程(bash)上

(3)现在关闭运行nginx的进程窗口会发现另外2个运行strace的窗口都有内容输出。

首先看下附着nginx进程的终端窗口的输出内容:
在这里插入图片描述

图2.4.3 附着到nginx进程上的strace工具有了输出

从图2.4.3中可以看出,信号是SIGHUP,sid_pid表示谁发来的信号,3253就是bash进程(nginx进程的父进程)。

接着看下附着bash进程的终端窗口的输出内容:
在这里插入图片描述

图2.4.4 附着到bash进程上的strace工具有了输出

图2.4.4所示信息有些复杂,尝试找一找有用的信息(kill在这里表示发送信号的意思)。

(1)开头为"kill(-23099, SIGHUP)"的这行,nginx进程的进程组(PGRP)ID就是23099,所以这行表示发送信号给这个数字的绝对值所在的进程组(kill后面如果有负值,一般代表发送信号给一个进程组),也就是说,进程组ID为23099的所有进程都会收到SIGHUP的信号。

(2)kill(3253, SIGHUP)的这行,3253是bash进程自己的PID,bash在第一次收到SIGHUP信号时先把该信号发给session内的其他进程(不仅是上面的23099进程组的进程,如果有其他进程组,其他进程组也会收到SIGHUP信号(只要这些进程的session ID 相同),然后再次发送SIGHUP命令给自己,将自己杀死。下一行的“sid_pid=3253”也就说明了杀死了自己

2.5 终端关闭时如何让进程不退出

当终端关闭时,终端上运行的nginx进程就退出了。现在要解决的问题是,终端关闭时,如何让nginx进程不退出。设想一下,如果nginx进程拦截SIGHUP信号,是否可以?

2.5.1 nginx进程拦截SIGHUP信号

修改一下nginx.c。信号相关内容后面讲,这里写一小段代码,把该信号忽略掉。收到SIGHUP信号后,操作系统默认结束nginx进程,现在通过修改代码,告诉操作系统忽略掉该信号,操作系统就不会执行默认处理行为(不会结束该进程)。

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
int main(int argc, char *const *argv)
{
        printf("hello nginx\n");
        //系统函数,设置收到某个信号时的处理程序(用哪个函数来处理)
		signal(SIGHUP, SIG_IGN); //SIG_ING:代表我要求忽略该信号,请求操作系统不要执行默认的
							     //该信号处理动作(不要把本进程杀掉)。
        for(;;)
        {
                sleep(1);
                printf("休息1s\n");
        }
        printf("程序退出!再见!\n");
}

此时编译并执行,如图所示:
在这里插入图片描述

图2.5.1.1 strace工具输出前状态

关闭了nginc进程所在的bash父进程后,我们发现6408 bash进程没了,但是nginx进程依旧在,如图所示:

在这里插入图片描述

图2.5.1.2 关闭了nginc进程所在的bash父进程后strace工具输出后状态

nginx依旧存在,不过它的TT(终端)列显示变成了“?”,这表示没有对应的终端了,而且它的PPID(父进程ID)变成了1,正是前面介绍的老祖宗进程init的PID(进程ID),本来nginx进程的父进程是bash,但是bash被结束了,nginx进程变成孤儿进程,这种孤儿进程就被init进程收养了。

2.5.2 nginx进程和bash进程在不同的session中(不同的session ID)

这就涉及调用系统函数setid了。该函数用于建立一个新会话。修改nginx.c代码如下:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
int main(int argc, char *const *argv)
{
        printf("hello nginx\n");
        pid_t pid;
		
		pid = fork();//系统函数,用来创建新进程,后续会继续讲解,子进程会从这句fork调用之后开始
					 //执行,原来的父进程也会接着往下执行
					 //为什么调用fork()函数,而不直接创建会话?是因为主进程是进程组的组长,不允许调用setsid来建立会话
		printf("pid = %d \n", pid);
		if(pid < 0){
			printf("fork进程出错!\n");
		}else if(pid == 0){
			//若执行的是子进程,则该条件就会满足
			printf("子进程开始执行!\n");
			//创建新的session
			setsid();
			for(;;)
        	{
                sleep(1);
                printf("休息1s\n");
        	}
			return 0;
		}else{
			//父进程才会走到这里
			for(;;)
        	{
                sleep(1);
                printf("休息1s\n");
       		}
       		return 0;
		}
        printf("程序退出!再见!\n");
        return 0;
}

这里是调用fork创建了一个子进程(子进程创建成功后回和父进程并行运行),然后在子进程中调用setsid。

此时,子一个终端窗口编译、链接并运行nginx,如图,可以看到父进程和子进程都在运行之中。
在这里插入图片描述

图2.5.2.1 重新编译链接nginx.c并执行,此时父进程和子进程并行执行

可以清楚地看到,PID为16658的nginx进程的父进程ID(PID)是16657,但是16658和16657两个进程的SID并不相同。还可以发现调用fork函数创建出的子进程没有关联的终端(TT/TTY列显示为“?”)。

现在,把正显示nginx执行结果终端断开连接,再看下信息:
在这里插入图片描述

图2.5.2.2 关闭了nginc进程所在的bash父进程后strace工具输出后状态

可以发现PID15806的bash没有了,PID为16657的父进程也没了,但PID为166658的子进程还在,子进程变成了孤儿进程,被老祖宗init收养了,所以子进程的PPID变成了1。

2.5.3 直接使用setsid命令

setsid不但是个函数(可以在代码中使用),也是个命令(可以在命令行中使用)。该命令用于启动一个进程,而且能够使启动的进程在一个新的session中,这样终端关闭后进程就不会退出。

现在,我们"kill 166658" , 把剩余的nginx杀死,并把代码复原:

#include <stdio.h>
#include <unistd.h>
int main(int argc, char *const *argv)
{
        printf("hello nginx\n");
        for(;;)
        {
                sleep(1);
                printf("休息1s\n");
        }
        printf("程序退出!再见!\n");
        
}

再次编译gcc -o nginx nginx.c
在一个终端窗口执行命令:setsid ./nginx
在另一个终端窗口执行命令:ps -ef | grep -E "nginx|PID|bash"

在这里插入图片描述

图2.5.3.1 运行setsid ./nginx 命令后的执行情况

然后我们关闭nginx终端,依旧存在nginx进程:
在这里插入图片描述

图2.5.3.2 关闭nginx终端,显示终端进程的执行情况

可以看出,关闭后依然存在。

2.5.4 直接使用 nohup命令(no hang up 不挂断)

是否觉得这个命令似曾相识?前面介绍了一个终端断开信号(SIGHUP),看起来与这个命令很相似,都是hup。是的,使用nohup命令启动的程序会忽略(SIGHUP信号),与用程序编写忽略SIGHUP信号同理。

nohup命令有点与众不同,执行程序,我们看看:
nohup ./nginx

结果如图:
在这里插入图片描述

图2.5.4.1 使用nohup命令启动一个可执行程序

可以发现,本来屏幕上输出的内容,现在不输出了,光标停在屏幕上。这是nohup命令的特点,该命令会把输出重定向到当前目录的nohup.out文件中,程序需要执行10~20s才能发现nohup的尺寸有变化(变得大于0了)。所以,这种nohup文件的输出程序执行结果并不是实时输出,而是有一定的延迟。

看下当前目录结构:
在这里插入图片描述

图2.5.4.2 查看nohup命令的输出文件nohup.out的大小

查看当前的进程信息:
在这里插入图片描述

图2.5.4.3 查看当前的nginx进程信息

关闭nginx的终端后,查看当前的进程信息:
在这里插入图片描述

图2.5.4.4 关闭nginx的终端后,查看当前的进程信息

nginx依然存在,PPID变成了1,子进程变成了孤儿进程,被老祖宗init收养了。

2.6 后台执行(运行)的简单理解

后台执行(运行)的命令:
./nginx &

在这里插入图片描述

图2.6.1 使用"&"让程序在后台执行

此时,程序在后台执行了(直接输入./nginx执行方式可理解为在前台运行)。

那么,程序在后台运行和在前台运行有什么区别呢?

(1)如果程序在前台执行,在终端输入ls命令,是无法列出目录的;程序在前台执行终端只只能等待该程序指向完成才能继续执行其他程序。
(2)如果程序在前台执行,则按Ctl + C 组合键能够停止该进程的执行;如果程序在后台执行,按Ctl + C 组合键则无法停止该进程的执行。
(3)可以把前台执行的进程切换到前台,使用fg命令即可进行切换:
fg
nginx进程被切换到了前台,这时按Ctl + C组合键就可以停止该进程了。
(4)如果把终端连接断开,就会发现,就算nignx是后台进程,它也被关闭(退出)了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/661444.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

案例:从定性原因分析上升到定量原因分析

在定量原因分析时&#xff0c;主要是有四种定量思考的方法&#xff1a; 1、数据的居中趋势与离散程度分析&#xff1a;均值、标准差 2、 80-20分析&#xff1a;在所有的构成成分中&#xff0c;哪个成分占比最大 3、数据的相关性分析&#xff1a;是否存在强相关 4、敏感性分…

[进阶]Java:文件字符输入流、文件字符输出流

问&#xff1a;字节流读取中文输出可能会存在什么问题&#xff1f; 会乱码。或者内存溢出。 读取中文输出&#xff0c;哪个流更合适&#xff0c;为什么&#xff1f; 字符流更合适&#xff0c;最小单位是按照单个字符读取的。 代码演示如下&#xff1a; public class FileR…

[C++]vs2019运行c++报错:错误 C1075 “{”: 未找到匹配令牌

源码是从git拉下来的&#xff0c;但是我并没有改任何东西&#xff0c;结果报错超过100个&#xff0c;这个很明显不是代码问题&#xff0c;最后发现需要把LF换成CRLF&#xff0c;修改方法很简单&#xff0c;就是VS2019打开源代码右下角切换即可。如图 错误原因就是github下载的源…

【MySQL】不就是MySQL——多表查询

前言 嗨&#xff01;小伙伴们大家好呀&#xff0c;忙碌的一周就要开始&#xff01;在此之前我们学习的MySQL数据库的各种操作都是在一张表之中&#xff0c;今天我们学习要对多张表进行相关操作&#xff0c;相比较于单一的表来说&#xff0c;多张表操作相对复杂一些&#xff0c;…

【数据库三】数据库的存储引擎

存储引擎 1.存储引擎1.1 概念介绍1.2 常用存储引擎 2.MyISAM2.1 特点介绍2.2 支持的存储格式2.3 适用的生产场景 3.InnoDB3.1 特点介绍3.2 适用生产场景分析4.企业选择存储引擎依据 5.MyISAM和InnoDB的区别命令操作 1.存储引擎 1.1 概念介绍 MySQL数据库中的组件&#xff0c;负…

深层神经网络

1、深层网络中的前向传播 一个训练样本 x 前向传播 第一层需要计算 &#x1d467; [1] &#x1d464;[1]&#x1d465; &#x1d44f; [1]&#xff0c;&#x1d44e; [1] &#x1d454; [1] (&#x1d467; [1] )&#xff08;&#x1d465;可以看做 &#x1d44e; [0] &am…

软件工程导论期末救急包(中)

目录 用户需求 需求分析常用的分析方法 软件设计 创建良好设计的原则 内聚性 耦合性 UML中各种视图及其作用 用例视图VS逻辑视图 UML中的主要图及其作用 软件开发过程与UML可视化建模 MVC模式 MVVM模式 面向对象模型主要哪些模型组成&#xff1f; 概要设计阶段的基本任务是什…

联想小新 Pro 16 2022 锐龙版开启S3睡眠模式方法,解决S0睡眠发热耗电容易唤醒等烦恼

联想小新 Pro 16 2022 锐龙版&#xff0c;CPU为AMD Ryzen 7 6800H 默认为S0睡眠模式&#xff0c;经常发热睡死过去&#xff0c;并且无法禁止鼠标唤醒电脑 本文借助“Universal AMD Form Browser”软件&#xff0c;在固件层面修改笔记本的睡眠方式。 本文所用到的软件Univer…

【Unity】 基础入门 编译错误排查与调试方法

基础入门 编译错误排查与调试方法 一、常见编译错误原因1、环境问题2、代码命名问题二、代码调试方法1、基础调试方法2、高级玩法3、unity调试工具插件一、常见编译错误原因 1、环境问题 1、Win11系统不兼容部分unity版本 考虑换系统吧! 2、可能是系统权限问题,访问不到部分…

jmeter工具介绍

Jmeter性能测试工具介绍 Jmeter的背景介绍Jemter过程类元件介绍Jmeter结果查看类元件介绍Jmeter其他介绍 Jmeter背景介绍&#xff1a; Apache JMeter是Apache组织的开放源代码项目&#xff0c;是一个100%纯Java桌面应用&#xff0c;用于压力测试和性能测试。它最初被设计用于…

C++技能系列 ( 2 ) - const的几种使用【详解】

系列文章目录 C高性能优化编程系列 深入理解软件架构设计系列 高级C并发线程编程 C技能系列 期待你的关注哦&#xff01;&#xff01;&#xff01; 生活就是上帝发给你的一张手牌&#xff0c;无论多烂&#xff0c;你都得拿着。 Life is god give you a hand, no matter ho…

【前端面试手册】CSS系列-01

本专栏收录于《前端面试手册-CSS篇》如果该文章对您有帮助还希望你能点一个小小的订阅&#xff0c;来增加博主创作的动力✍&#x1f3fb; 一、什么是盒子模型&#xff0c;说说你的理解&#xff1f; 首先&#xff0c;如果你要对一个文档进行布局的时候&#xff0c;浏览器的渲染…

[进阶]Java:对象序列化、反序列化

对象序列化&#xff1a; 使用到的流是对象字节输出流&#xff1a;ObjectOutputStream作用&#xff1a;以内存为基础&#xff0c;把内存中的对象存储到磁盘文件中去。称为对象序列化。 代码演示如下&#xff1a; 学生类&#xff1a; /**对象如果要序列化一定要实现Serializab…

力扣题库刷题笔记7--N字型变换

1、题目如下&#xff1a; 2、个人Python代码实现&#xff1a; 看到此题的第一反应就是&#xff0c;生成一个类似二维数组的多个字符串&#xff0c;然后用个标志位控制N字符中字符的方向&#xff0c;例如flag True&#xff0c;在每次循环时候以flag flag * -1来控制。 由于示例…

Oracle-ASM磁盘组HIGH模式丢盘问题处理

背景: 用户一套Oracle19c的RAC集群ASM磁盘组使用了3个存储作为HIGH以及NORMAL冗余模式&#xff0c;每个存储分别对应一个failgroup&#xff0c;其中2个存储出现了故障导致ASM磁盘组对应的failgroup磁盘全部offline&#xff0c;在存储恢复正常之后&#xff0c;需要将offline的磁…

2020年全国硕士研究生入学统一考试管理类专业学位联考英语(二)试题

2020年英语二联考真题 一、完形填空 Directions: Read the following text. Choose the best word for each numbered blank and mark A, B, C or D on the ANSWER SHEET (10 points) Being a good parent is what every parent would like to be. But defining what it mea…

《Java黑皮书基础篇第10版》 第17章【习题】

Java语言程序设计 习题第十七章 17.2章节习题 17.1什么是文本文件&#xff0c;什么是二进制文件&#xff1f;可以使用文本编辑器来查看文本文件或者二进制文件吗&#xff1f; 文本文件是字符组成的文件&#xff0c;二进制文件是0和1组成的文件 文本编辑器只能访问文本文件 17…

一文教你彻底学会SPI协议

一文教你彻底学会IIC协议 一.概况SPI二.SPI连接2.1 一主一从2.2 一主多从 三.SPI通信过程3.1 CPOL&#xff08;极性&#xff09;和CPHA&#xff08;相位&#xff09;3.2 SPI时序图3.1 SPI起始信号3.2 SPI停止信号3.3 数据的有效性 四.代码实例 一.概况SPI SPI 协议是由摩托罗拉…

腾讯云服务器开Minecraft配置怎么选择?

腾讯云服务器Minecraft我的世界服务器配置怎么选择&#xff1f;10人以内玩2核4G就够用了&#xff0c;腾讯云开我的世界服务器选择轻量应用服务器就够了&#xff0c;轻量CPU采用至强白金处理器&#xff0c;大型整合包一般1.12版本的&#xff0c;轻量2核4G配置都差不多的&#xf…

智慧加油站卸油作业行为分析算法 opencv

智慧加油站卸油作业行为分析系统通过opencvpython网络模型技术&#xff0c;智慧加油站卸油作业行为分析算法实现对卸油作业过程的实时监测。当现场出现卸油作业时人员离岗&#xff0c;打电话人员抽烟等违规行为&#xff0c;灭火器未正确摆放&#xff0c;明火和烟雾等异常状态&a…