进程间关系与守护进程
一、进程组
1.1、什么是进程组
提到进程的概念, 其实每一个进程除了有一个进程 ID(PID)之外 还属于一 个进程组。进程组是一个或者多个进程的集合, 一个进程组可以包含多个进程。 每一 个进程组也有一个唯一的进程组 ID(PGID), 并且这个 PGID 类似于进程 ID, 同样是 一个正整数, 可以存放在 pid_t 数据类型中。
ps -eo pid,pgid,ppid,comm | grep test结果如下
PID PGID PPID COMMAND
2830 2830 2259 test-e 选项表示 every 的意思, 表示输出每一个进程信息
-o 选项以逗号操作符(,)作为定界符, 可以指定要输出的列
1.2、组长进程
每一个进程组都有一个组长进程。 组长进程的 ID 等于其进程 ID。我们可以通过 ps 命 令看到组长进程的现象:
ps -o pid,pgid,ppid,comm | cat# 输出结果
PID PGID PPID COMMAND
2806 2806 2805 bash
2880 2880 2806 ps
2881 2880 2806 cat
从结果上看 ps 进程的 PID 和 PGID 相同, 那也就是说明 ps 进程是该进程组的组长进 程, 该进程组包括 ps 和 cat 两个进程。
- 进程组组长的作用: 进程组组长可以创建一个进程组或者创建该组中的进程
- 进程组的生命周期: 从进程组创建开始到其中最后一个进程离开为止。注意:主要某个进程组中有一个进程存在, 则该进程组就存在, 这与其组长进程是否已经终 止无关。
二、会话
2.1、什么是会话
刚刚谈到了进程组的概念, 那么会话又是什么呢? 会话其实和进程组息息相关, 会话可以看成是一个或多个进程组的集合, 一个会话可以包含多个进程组。每一个会 话也有一个会话 ID(SID)
通常都是使用管道将几个进程编成一个进程组。 如上图的进程组 2 和进程组 3 可能是由下列命令形成的:
Shell
[node@localhost code]$ proc2 | proc3 &
[node@localhost code]$ proc4 | proc5 | proc6 &
# &表示将进程组放在后台执行
举一个例子观察一下这个现象:
Shell
# 用管道和 sleep 组成一个进程组放在后台运行
[node@localhost code]$ sleep 100 | sleep 200 | sleep 300 &
# 查看 ps 命令打出来的列描述信息
[node@localhost code]$ ps axj | head -n1
# 过滤 sleep 相关的进程信息
[node@localhost code]$ ps axj | grep sleep | grep -v grep
# a 选项表示不仅列当前⽤户的进程,也列出所有其他⽤户的进程
# x 选项表示不仅列有控制终端的进程,也列出所有⽆控制终端的进程
# j 选项表示列出与作业控制相关的信息, 作业控制后续会讲
# grep 的-v 选项表示反向过滤, 即不过滤带有 grep 字段相关的进程
# 结果如下PPID PID PGID SID TTY TPGID STAT UID TIME
COMMAND
2806 4223 4223 2780 pts/2 4229 S 1000 0:00 sleep
100
2806 4224 4223 2780 pts/2 4229 S 1000 0:00 sleep
200
2806 4225 4223 2780 pts/2 4229 S 1000 0:00 sleep
300
从上述结果来看 3 个进程对应的 PGID 相同, 即属于同一个进程组。
2.2、如何创建会话
可以调用 setseid 函数来创建一个会话, 前提是调用进程不能是一个进程组的组长。
C
#include <unistd.h>
/**功能:创建会话*返回值:创建成功返回 SID, 失败返回-1
*/
pid_t setsid(void);
该接口调用之后会发生:
- 调用进程会变成新会话的会话首进程。 此时, 新会话中只有唯一的一个进程
- 调用进程会变成进程组组长。 新进程组 ID 就是当前调用进程 ID
- 该进程没有控制终端。 如果在调用 setsid 之前该进程存在控制终端, 则调 用之后会切断联系
需要注意的是: 这个接口如果调用进程原来是进程组组长, 则会报错, 为了避免这种情况, 我们通常的使用方法是先调用 fork 创建子进程, 父进程终止, 子进程继续执行, 因为子进程会继承父进程的进程组 ID, 而进程 ID 则是新分配的, 就不会出现错误的情况。
2.3、会话 ID(SID)
上边我们提到了会话 ID, 那么会话 ID 是什么呢? 我们可以先说一下会话首进程, 会 话首进程是具有唯一进程 ID 的单个进程, 那么我们可以将会话首进程的进程 ID 当做 是会话 ID。注意:会话 ID 在有些地方也被称为 会话首进程的进程组 ID, 因为会话首 进程总是一个进程组的组长进程, 所以两者是等价的。
三、控制终端
先说一下什么是控制终端:
在 UNIX 系统中,用户通过终端登录系统后得到一个 Shell 进程,这个终端成为 Shell 进程的控制终端。控制终端是保存在 PCB 中的信息,我们知道 fork 进程会复制 PCB 中的信息,因此由 Shell 进程启动的其它进程的控制终端也是这个终端。默认情况下没有重定向,每个进程的标准输入、标准输出和标准错误都指向控制终端,进程从标准输入读也就是读用户的键盘输入,进程往标准输出或标准错误输出写也就是输出到显示器上。另外会话、进程组以及控制终端还有一些其他的关系,我们在下边详细介绍一下:
- 一个会话可以有一个控制终端,通常会话首进程打开一个终端(终端设备或 伪终端设备)后,该终端就成为该会话的控制终端。
- 建立与控制终端连接的会话首进程被称为控制进程。
- 一个会话中的几个进程组可被分成一个前台进程组以及一个或者多个后台进程组。
- 如果一个会话有一个控制终端,则它有一个前台进程组,会话中的其他进程 组则为后台进程组。
- 无论何时进入终端的中断键(ctrl+c)或退出键(ctrl+\),就会将中断信号 发送给前台进程组的所有进程。
- 如果终端接口检测到调制解调器(或网络)已经断开,则将挂断信号发送给 控制进程(会话首进程)。
这些特性的关系如下图所示:
四、作业控制
4.1、什么是作业(job)和作业控制(Job Control)
作业是针对用户来讲,用户完成某项任务而启动的进程,一个作业既可以只包含 一个进程,也可以包含多个进程,进程之间互相协作完成任务, 通常是一个进程管道。
Shell 分前后台来控制的不是进程而是作业 或者进程组。一个前台作业可以由多 个进程组成,一个后台作业也可以由多个进程组成,Shell 可以同时运⾏一个前台 作业和任意多个后台作业,这称为作业控制。
例如下列命令就是一个作业,它包括两个命令,在执⾏时 Shell 将在前台启动由两 个进程组成的作业:
Shell
[node@localhost code]$ cat /etc/filesystems | head -n 5
运⾏结果如下所示:
Shell
xfs
ext4
ext3
ext2
nodev proc
4.2、作业号
放在后台执⾏的程序或命令称为后台命令,可以在命令的后面加上&符号从而让 Shell 识别这是一个后台命令,后台命令不用等待该命令执⾏完成,就可立即接收 新的命令,另外后台进程执行完后会返回一个作业号以及一个进程号(PID)。
例如下面的命令在后台启动了一个作业, 该作业由两个进程组成, 两个进程都在后台运⾏:
[node@localhost code]$ cat /etc/filesystems | grep ext &
执⾏结果如下:
Shell
[1] 2202
ext4
ext3
ext2
# 按下回车
[1]+ 完成 cat /etc/filesystems | grep --color=auto ext
- 第一⾏表示作业号和进程 ID, 可以看到作业号是 1, 进程 ID 是 2202
- 第 3-4 ⾏表示该程序运⾏的结果, 过滤/etc/filesystems 有关 ext 的内容
- 第 6 号分别表示作业号、默认作业、作业状态以及所执⾏的命令
关于默认作业:对于一个用户来说,只能有一个默认作业(+),同时也只能有一 个即将成为默认作业的作业(-),当默认作业退出后,该作业会成为默认作业。
- +:表示该作业号是默认作业
- - :表示该作业即将成为默认作业
- 无符号: 表示其他作业
4.3、作业状态
常见的作业状态如下表所示:
作业状态 | 含义 |
---|---|
正在运行【Running】 | 后台作业(&),表示正在运行 |
完成【Done】 | 作业已完成,返回的状态码为0 |
完成并退出【Done(code)】 | 作业已完成并退出,返回的状态码为非0 |
已停止【Stopped】 | 前台作业,当前 Ctrl+Z 挂起 |
已终止【Terminated】 | 作业被终止 |
4.4、作业的挂起与切回
4.4.1、作业挂起
执⾏某个作业时,可以通过 Ctrl+Z 键将该作业挂起,然后 Shell 会显示相 关的作业号、状态以及所执⾏的命令信息。
例如运⾏一个死循环的程序, 通过 Ctrl+Z 将该作业挂起, 观察一下对应的作业状态:
C
#include <stdio.h>
int main()
{while (1){printf("hello\n");}return 0;
}
运⾏这个程序, 通过 Ctrl+Z 将该作业挂起:
Shell
# 运行可执行程序
[node@localhost code]$ ./test
#键入 Ctrl + Z 观察现象
运⾏结果如下:
Shell
# 结果依次对应作业号 默认作业 作业状态 运行程序信息
[1]+ 已停止 ./test7
可以发现通过 Ctrl+Z 将作业挂起, 该作业状态已经变为了停止状态
4.4.2、作业切回
如果想将挂起的作业切回,可以通过 fg 命令,fg 后面可以跟作业号或作业的命令名称。如果参数缺省则会默认将作业号为 1 的作业切到前台来执⾏,若当前系 统只有一个作业在后台进⾏,则可以直接使用 fg 命令不带参数直接切回。 具体的参数参考如下:
参数 | 含义 |
---|---|
%n | n为整数,表示作业号 |
%string | 以字符串开头的命令所对应的作业 |
%?string | 包含字符串的命令所对应的作业 |
%+ 或 %% | 最近提交的一个作业 |
%- | 倒数第二个提交的作业 |
例如把刚刚挂起来的 ./test 作业切回到前台:
Shell
[node@localhost code]$ fg %%
运⾏结果为开始无限循环打印 hello, 可以发现该作业已经切换到前台了。
注意: 当通过 fg 命令切回作业时,若没有指定作业参数,此时会将默认作业切 到前台执行,即带有“+”的作业号的作业
4.5、查看后台执行或挂起的作业
可以直接通过输入 jobs 命令查看本用户当前后台执⾏或挂起的作业
- 参数-l 则显示作业的详细信息
- 参数-p 则只显示作业的 PID
例如, 先在后台及前台运⾏两个作业, 并将前台作业挂起, 来用 jobs 命令 查看作业相关的信息:
Shell
# 在后台运行一个作业 sleep
[node@localhost code]$ sleep 300 &
# 运行刚才的死循环可执行程序
[node@localhost code]$ ./test
# 键入 Ctrl + Z 挂起作业
# 使用 jobs 命令查看后台及挂起的作业
[node@localhost code]$ jobs -l
运⾏结果如下所示:
Shell
# 结果依次对应作业号 默认作业 作业状态 运行程序信息
[1]- 2265 运行中 sleep 300 &
[2]+ 2267 停止 ./test7
4.6、作业控制相关的信号
上面我们提到了键入 Ctrl + Z 可以将前台作业挂起,实际上是将 STGTSTP 信号 发送至前台进程组作业中的所有进程, 后台进程组中的作业不受影响。 在 unix 系统中, 存在 3 个特殊字符可以使得终端驱动程序产生信号, 并将信号发送至前 台进程组作业, 它们分别是:
- Ctrl + C: 中断字符, 会产生 SIGINT 信号
- Ctrl + \: 退出字符, 会产生 SIGQUIT 信号
- ▪ Ctrl + Z:挂起字符, 会产生 STGTSTP 信号
终端的 I/O(即标准输入和标准输出)和终端产生的信号总是从前台进程组作业连接 打破实际终端。
五、守护进程
Daemon.hpp
C++
#pragma once#include <iostream>
#include <cstdlib>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>const char *root = "/";
const char *dev_null = "/dev/null";void Daemon(bool ischdir, bool isclose)
{// 1. 忽略可能引起程序异常退出的信号signal(SIGCHLD, SIG_IGN);signal(SIGPIPE, SIG_IGN);// 2. 让自己不要成为组长if (fork() > 0)exit(0);// 3. 设置让自己成为一个新的会话, 后面的代码其实是子进程在走setsid();// 4. 每一个进程都有自己的 CWD,是否将当前进程的 CWD 更改成为 / 根目录if (ischdir)chdir(root);// 5. 已经变成守护进程啦,不需要和用户的输入输出,错误进行关联了if (isclose){close(0);close(1);close(2);}else{// 这里一般建议就用这种int fd = open(dev_null, O_RDWR);if (fd > 0){dup2(fd, 0);dup2(fd, 1);dup2(fd, 2);close(fd);}}
}
六、如何将服务守护进程化
C++
// ./server port
int main(int argc, char *argv[])
{if (argc != 2){std::cout << "Usage : " << argv[0] << " port" <<std::endl;return 0;}uint16_t localport = std::stoi(argv[1]);Daemon(false, false);std::unique_ptr<TcpServer> svr(new TcpServer(localport, HandlerRequest));svr->Loop();return 0;
}
相关文章:

进程间关系与守护进程
一、进程组 1.1、什么是进程组 提到进程的概念, 其实每一个进程除了有一个进程 ID(PID)之外 还属于一 个进程组。进程组是一个或者多个进程的集合, 一个进程组可以包含多个进程。 每一 个进程组也有一个唯一的进程组 ID(PGID), 并且这个 PG…...

金山翻译接口逆向
网址(加密后):aHR0cHM6Ly93d3cuaWNpYmEuY29tL3RyYW5zbGF0ZQ 文章目录 抓包sign值结果加密 逆向sign值第一步第二步1.2.3. 解密content第一步1.2.3. 抓包 F12 -> 翻译框输入spider -> 点击Fetch/XHR -> 找到接口 index.php? 开头的…...
unified-runtime编译与验证
unified-runtime编译与验证 一.创建容器二.编译unified-runtime三.生成一个cuda ptx kernel四.API测试 unified-runtime编译与验证 一.创建容器 docker run --gpus all --shm-size32g -ti \-e NVIDIA_VISIBLE_DEVICESall --privileged --nethost \--rm -it \-v $PWD:/home \-…...
【Python】最详细--基础语法
Python是一种强大且易于学习的编程语言,广泛用于各种应用程序的开发,如web开发、数据科学、人工智能等。以下是一些Python的基础知识: 1. Python的注释 Python的注释用于在代码中添加说明,以提高代码的可读性。注释在代码执行时…...
二叉树基础:什么样的二叉树适合用数组来存储?
二叉树基础:什么样的二叉树适合用数组来存储? 在计算机科学中,二叉树是一种非常重要的数据结构。它具有许多应用,如搜索、排序、表达式解析等。在存储二叉树时,我们可以使用多种方法,其中一种是使用数组。但是,并不是所有的二叉树都适合用数组来存储。那么,什么样的二…...

iTOP-RK3568开发板独立NPU通过算法加特应用到以下的场景
iTOP-3568开发板采用瑞芯微RK3568处理器,内部集成了四核64位Cortex-A55处理器。主频高达2.0Ghz,RK809动态调频。集成了双核心架构GPU,ARM G52 2EE、支持OpenGLES1.1/2.0/3.2、OpenCL2.0、Vulkan1.1、内嵌高性能2D加速硬件。 内置独立NPU,算力…...

Java基于SpringBoot微信小程序的跳蚤市场系统设计与实现(lw+数据库+讲解等)
项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念,提供了一套默认的配置,让开发者可以更专注于业务逻辑而不是配置文件。Spring Boot 通过自动化配置和约…...
【分布式微服务云原生】《Redis 的高效之道:线程模型、IO 模型与 Reactor 模型全解析》
标题:《分布式缓存Redis 的高效之道:线程模型、IO 模型与 Reactor 模型全解析》 摘要:本文深入探讨分布式缓存 Redis 的 I线程模型、IO 模型以及 Reactor 模型。详细介绍了 Redis 在不同版本中的线程变化、IO 模型的特点和工作流程ÿ…...

科研类型PPT的制作技巧
目录 科研类型PPT的制作技巧 荣誉: 首页:ppt开头结尾 小标题 重点标记:加粗红色下划线 使用三线表 图片,文本排版 一、明确目的与受众分析 二、基础设计原则 三、内容组织与呈现 四、绘图与模型制作 五、其他注意事项 科研类型PPT的制作技巧 荣誉: 首页:ppt开…...

rom定制系列------小米6x_MIUI14_安卓13刷机包修改写入以及功能定制 界面预览
在接待一些定制化系统中。有很多工作室或者一些特殊行业的友友需要在已有固件基础上简略修改其中的功能。方便使用。例如usb调试默认开启。usb安装设置以及usb安装与内置删减一些app的定制服务。今天给友友预览其中小米6X此款机型定制相关的一些界面与功能演示。 定制机型以及…...

线性代数基础02
目录 1.向量 1.1向量的定义 1.2向量的运算 1.2.1向量加法 1.2.2向量数乘 1.2.3向量点积 1.3矩阵的特征值和特征向量 1.4向量的模 1.4.1向量的模的定义 1.4.2向量的模的几何解释 1.4.3向量的模的性质 1.5向量的内积 1.5.1向量的内积的定义 1.5.2向量的内积的几何解…...
「4.4」祖孙询问
「4.4」祖孙询问 题目描述 已知一棵 n 个节点的有根树。有 m 个询问,每个询问给出了一对节点的编号 x 和 y,询问 x 与 y 的祖孙关系。 输入格式 输入第一行包括一个整数 n 表示节点个数; 接下来 n 行每行一对整数对 a 和 b 表示 a 和 b 之…...

Datawhale 组队学习 文生图 Prompt攻防 task03随笔
这期我们从不同角度切入探讨赛题的进阶思路 思路1:对比不同大模型 首先我们可以选择尝试不同的大模型,使用更复杂的大模型可以提高文本改写的质量和效果。随着模型大小的增加,其表示能力也随之增强,能够捕捉更细微的语言特征和语…...

游戏投屏软件有哪些?分享这10款比较好用的!
说到投屏,这个事情我还是比较有发言权的! 一般手机下载个APP,然后就可以通过WiFi、蓝牙或者USB进行连接投屏啦,下面是国内比较主流的一些游戏投屏软件,可以根据他们的优缺点进行选择哦! 01.幕连 国内首款…...

[Unity Demo]从零开始制作空洞骑士Hollow Knight第十六集(下篇):制作小BOSS龙牙哥
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、制作小BOSS龙牙哥 1.导入素材制作动画2.制作两种攻击行为3.制作从惊醒到转身到走路or跑步行为总结 前言 hello大家好久没见,之所以隔了一天时间…...

顺序表算法题【不一样的解法!】
本章概述 算法题1算法题2算法题3彩蛋时刻!!! 算法题1 力扣:移除元素 我们先来看这个题目的要求描述: 把与val相同数值的元素移除掉,忽略元素的相对位置变化,然后返回剩下与val值不同的元素个数…...
VuePress的基本常识
今天大概了解了一下Vuepress,感觉很棒,看着极其简单,自己也想做一个,后续我大概率也会做一个用Vuepress为基础做的博客网站,很酷~ 哈哈哈,下面是我今天学习Vuepress的一些内容,简单分享下&#…...
深入解析Vue2与Vue3的区别与Vue3的提升
Vue.js作为一款流行的前端框架,自发布以来,凭借其简洁的语法、灵活的组件化和高效的性能,赢得了众多开发者的喜爱。随着Vue3的发布,许多新特性和新功能也应运而生。那么,Vue2与Vue3究竟有哪些区别呢?Vue3又…...
认识python数据分析
Python作为一种高效、灵活且易于学习的编程语言,在数据分析领域展现出了强大的应用潜力。 从数据清洗、预处理到复杂的统计分析、可视化及机器学习模型的构建,Python提供了丰富的库和框架,极大地简化了数据分析的流程,提高了工作…...

以太网交换安全:MAC地址漂移与检测(实验:二层环路+网络攻击)
一、什么是MAC地址漂移? MAC地址漂移是指网络中设备的MAC地址在运行过程中发生变化的现象。 MAC地址是用于唯一标识网络中的设备。 MAC地址漂移是指交换机上一个VLAN内有两个端口学习到同一个MAC地址,后学习到的MAC地址表项覆盖原MAC地址表项的现象。…...

JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...

微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...