【在Linux世界中追寻伟大的One Piece】进程间关系与守护进程

目录

1 -> 进程组

1.1 -> 什么是进程组

1.2 -> 组长进程

2 -> 会话

2.1 -> 什么是会话

2.2 -> 如何创建会话

2.3 -> 会话ID(SID)

3 -> 控制终端

4 -> 作业控制

4.1 -> 什么是作业(job)和作业控制(Job Control)

4.2 -> 作业号

4.3 -> 作业状态

4.4 -> 作业的挂起与切回

4.4.1 -> 作业挂起

4.4.2 -> 作业切回

4.5 -> 查看后台执行或挂起的作业

4.6 -> 作业控制相关的信号

5 -> 守护进程

6 -> 如何将服务守护进程化


1 -> 进程组

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命令看到组长进程的现象:

[node@localhost code]$ 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 -> 会话

2.1 -> 什么是会话

会话其实和进程组息息相关,会话可以看成是一个或多个进程组的集合, 一个会话可以包含多个进程组。每一个会话也有一个会话ID(SID)。

通常我们都是使用管道将几个进程编成一个进程组。 如上图的进程组2和进程组3可能是由下列命令形成的:

[node@localhost code]$ proc2 | proc3 &
[node@localhost code]$ proc4 | proc5 | proc6 &
# &表示将进程组放在后台执行

举一个例子观察一下这个现象:

# 用管道和 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函数来创建一个会话, 前提是调用进程不能是一个进程组的组长。

#define _CRT_SECURE_NO_WARNINGS 1#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, 因为会话首进程总是一个进程组的组长进程, 所以两者是等价的。

3 -> 控制终端

在UNIX系统中,用户通过终端登录系统后得到一个Shell进程,这个终端成为Shell进程的控制终端。控制终端是保存在PCB中的信息,我们知道fork进程会复制PCB中的信息,因此由Shell进程启动的其它进程的控制终端也是这个终端。默认情况下没有重定向,每个进程的标准输入、标准输出和标准错误都指向控制终端,进程从标准输入读也就是读用户的键盘输入,进程往标准输出或标准错误输出写也就是输出到显示器上。另外会话、进程组以及控制终端还有一些其他的关系,我们在下边详细介绍一下:

  • 一个会话可以有一个控制终端,通常会话首进程打开一个终端(终端设备或伪终端设备)后,该终端就成为该会话的控制终端。
  • 建立与控制终端连接的会话首进程被称为控制进程
  • 一个会话中的几个进程组可被分成一个前台进程组以及一个或者多个后台进程组
  • 如果一个会话有一个控制终端,则它有一个前台进程组,会话中的其他进程组则为后台进程组。
  • 无论何时进入终端的中断键(ctrl+c)退出键(ctrl+\),就会将中断信号发送给前台进程组的所有进程。
  • 如果终端接口检测到调制解调器(或网络)已经断开,则将挂断信号发送给控制进程(会话首进程)。

这些特性的关系如下图所示:

4 -> 作业控制

4.1 -> 什么是作业(job)和作业控制(Job Control)

作业是针对用户来讲,用户完成某项任务而启动的进程,一个作业既可以只包含一个进程,也可以包含多个进程,进程之间互相协作完成任务, 通常是一个进程管道。

Shell分前后台来控制的不是进程而是作业 或者进程组。一个前台作业可以由多个进程组成,一个后台作业也可以由多个进程组成,Shell可以同时运⾏一个前台作业和任意多个后台作业,这称为作业控制

例如下列命令就是一个作业,它包括两个命令,在执⾏时Shell将在前台启动由两个进程组成的作业。

[node@localhost code]$ cat /etc/filesystems | head -n 5

运行结果如下:

xfs
ext4
ext3
ext2
nodev proc

4.2 -> 作业号

放在后台执⾏的程序或命令称为后台命令,可以在命令的后面加上&符号从而让Shell识别这是一个后台命令,后台命令不用等待该命令执⾏完成,就可立即接收新的命令,另外后台进程执行完后会返回一个作业号以及一个进程号(PID)。

例如下面的命令在后台启动了一个作业, 该作业由两个进程组成, 两个进程都在后台运⾏:

[node@localhost code]$ cat /etc/filesystems | grep ext &

运行结果如下:

[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将该作业挂起, 观察一下对应的作业状态:

#define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h>int main()
{while (1){printf("hello\n");}return 0;
}

下面运⾏这个程序, 通过Ctrl+Z将该作业挂起:

# 运行可执行程序
[node@localhost code]$ ./test
#键入 Ctrl + Z 观察现象

运行结果如下:

# 结果依次对应作业号 默认作业 作业状态 运行程序信息
[1]+ 已停止
./test7

可以发现通过Ctrl+Z将作业挂起, 该作业状态已经变为了停止状态。

4.4.2 -> 作业切回

如果想将挂起的作业切回,可以通过fg命令,fg后面可以跟作业号或作业的命令名称。如果参数缺省则会默认将作业号为1的作业切到前台来执⾏,若当前系统只有一个作业在后台进⾏,则可以直接使用fg命令不带参数直接切回。 具体的参数参考如下:

参数含义
%nn为正整数,表示作业号
%string以字符串开头的命令所对应的作业
%?string包含字符串的命令所对应的作业
%+或%%最近提交的一个作业
%-倒数第二个提交的作业

例如我们把刚刚挂起来的./test作业切回到前台:

[node@localhost code]$ fg %%

运⾏结果为开始无限循环打印hello, 可以发现该作业已经切换到前台了。

注意: 当通过fg命令切回作业时,若没有指定作业参数,此时会将默认作业切到前台执行,即带有"+"的作业号的作业。

4.5 -> 查看后台执行或挂起的作业

我们可以直接通过输入jobs命令查看本用户当前后台执⾏或挂起的作业。

  • 参数-l 则显示作业的详细信息。
  • 参数-p 则只显示作业的PID。

例如, 我们先在后台及前台运⾏两个作业, 并将前台作业挂起, 来用jobs命令查看作业相关的信息:

# 在后台运行一个作业 sleep
[node@localhost code]$ sleep 300 &


# 运行刚才的死循环可执行程序
[node@localhost code]$ ./test


# 键入 Ctrl + Z 挂起作业
# 使用 jobs 命令查看后台及挂起的作业
[node@localhost code]$ jobs -l

运行结果如下:

# 结果依次对应作业号 默认作业 作业状态 运行程序信息
[1]- 2265 运行中 sleep 300 &
[2]+ 2267 停止 ./test7

4.6 -> 作业控制相关的信号

上面我们提到了键Ctrl + Z可以将前台作业挂起,实际上是将STGTSTP信号发送至前台进程组作业中的所有进程, 后台进程组中的作业不受影响。 在unix系统中, 存在3个特殊字符可以使得终端驱动程序产生信号, 并将信号发送至前台进程组作业, 它们分别是:

  • Ctrl + C:中断字符,会产生SIGINT信号。
  • Ctrl + \:退出字符,会产生SIGQUIT信号。
  • Ctrl + Z:挂起字符,会产生STGTSTP信号。

终端的I/O(即标准输入和标准输出)和终端产生的信号总是从前台进程组作业连接打破实际终端。可以通过下图看到作业控制的功能:

5 -> 守护进程

#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);}}
}

6 -> 如何将服务守护进程化

// ./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;
}

感谢各位大佬支持!!!

互三啦!!!

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

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

相关文章

【他山之石】优化 JavaScript 的乐趣与价值(下)

前言 继本文的 上篇 发表之后&#xff0c;没想到反响还挺好&#xff0c;看来大家在 JS 优化的问题上越来越注重“与国际接轨”了。一起来看本文的下篇&#xff0c;也是干货满满。 文章目录 6. Avoid large objectsWhat the eff should I do about this? 7. Use eval8. Use str…

Linux用户账号管理

目录 一、useradd 创建新用户 二、usermod 修改用户账号 三、userdel 删除用户账号 四、passwd 设置或更改用户密码 五、who 或 w 查看当前登录用户 六、切换用户 6.1. su命令切换用户 6.2. sudo授权命令 6.2.1. sudo的特性 6.2.2. sudo的相关文件 6.3. exit退出 6…

自制数据库迁移工具-C版-04-HappySunshineV1.4-(支持Gbase8a、PG)

目录 一、环境信息 二、简述 三、架构图 四、升级点 五、支持功能 六、安装包下载地址 七、配置参数介绍 八、安装步骤 1、配置环境变量 2、生效环境变量 3、检验动态链接是否正常 4、修改配置文件MigrationConfig.txt &#xff08;1&#xff09;Gbase8a -> Gba…

Axios基本语法和前后端交互

Axios是一个js框架&#xff0c;用于发送ajax请求。 一、导入 // node中&#xff0c;使用npm安装 npm install axios // HTML中&#xff0c;使用cdn安装 <script src"https://unpkg.com/axios/dist/axios.min.js"></script> 二、基本使用 // 使用axios…

x264中的cabac编码实现

typedef struct { /* state */ int i_low; //概率状态的范围low int i_range; //当前概率状态 范围range /* bit stream */ int i_queue; //stored with an offset of -8 for faster asm 队列中可输出的bits 个数&#xff0c;-8 开始&#xff0c;是为了方便asm优化 int i_byt…

数据防泄密系统的构建与功能分析(实用物料)

一、构建1、需求分析&#xff1a;明确企业需要保护的敏感数据类型&#xff08;如商业机密、研发资料等&#xff09;及其潜在的泄露途径&#xff08;如网络传输、文件共享、打印复印等&#xff09;。 2、策略&#xff1a;根据需求分析结果&#xff0c;制定详细的数据防泄密策略…

数字逻辑电路-加法器

目录 半加器和全加器 半加器 ​全加器 集成全加器 利用全加器实现二进制的乘法功能 加法器 半加器和全加器 半加器 不考虑低位进位的加法。 本位为s&#xff0c;进位为c。 全加器 多了一个相邻低位来的进位数。 集成全加器 左上角和右下角那两个是不用的。 利用全加器…

Selenium通过ActionBuilder模拟鼠标操作直接移动到指定坐标的注意事项

在目前&#xff08;2024-09-18&#xff09;得Selenium官方手册中&#xff0c;模拟鼠标操作基本上都是通过ActionChains完成的&#xff0c;唯独有一动作&#xff0c;是通过ActionBuilder完成的。 而前者ActionChains&#xff0c;主要是通过offset&#xff0c;也就是坐标偏移量来…

RK3568笔记五十九:FastSAM部署

若该文为原创文章,转载请注明原文出处。 记录FastSAM训练到部署全过程,转换模型和yolov8一样。 一、介绍 Fast Segment Anything Model (FastSAM) 是一种基于 CNN 的新型实时解决方案,可用于 Segment Anything 任务。该任务旨在根据各种可能的用户交互提示分割图像中的任何…

AT24CXX系列eeprom的相关知识总结

常用的eeprom存储器件有很多容量类型&#xff0c;AT系列的eeprom有at24c01,at24c02…at24c1024等。我们来做一个总结。 1.常见的型号含义 at24c01&#xff1a;表示1kbit&#xff08;128BYTE*8&#xff09; at24c02&#xff1a;表示2kbit&#xff08;256BYTE*8&#xff09; . .…

pybind11 学习笔记

pybind11 学习笔记 0. 一个例子1. 官方文档1.1 Installing the Library1.1.1 Include as A Submodule1.1.2 Include with PyPI1.1.3 Include with Conda-forge 1.2 First Steps1.2.1 Separate Files1.2.2 PYBIND11_MODULE() 宏1.2.3 example.cpython-38-x86_64-linux-gnu.so 的…

二百六十四、Java——Java采集Kafka主题A的JSON数据,解析成一条条数据,然后写入Kafka主题B中

一、目的 由于Hive是单机环境&#xff0c;因此庞大的原始JSON数据在Hive中解析的话就太慢了&#xff0c;必须放在Hive之前解析成一个个字段、一条条CSV数据 二、IDEA创建SpringBoot项目 三、项目中各个文件 3.1 pom.xml <?xml version"1.0" encoding"UTF…

java: 警告: 源发行版 17 需要目标发行版 17(100% 解决)

1. 问题说明 Idea启动Springboot服务报错&#xff1a;java: 警告: 源发行版 17 需要目标发行版 17 2. 解决方案 Project Structure指定jdk版本为我们当前使用的版本&#xff1b; Java Compiler指定jdk为我们当前使用的版本&#xff1b; Invalidate Caches重启Idea。 如果还…

小商品市场配电系统安全用电解决方案

1.概述 随着市场经济的快速发展和人民生活水平的不断提高,全国各地相继建起了大批大型小商品批发市场,此类市场以其商品种类繁多、价格实惠、停车方便等特点吸引了大量的顾客,成为人们日常光顾的重要场所,地方便了广大人民群众的日常生活。 小商品市场集商品销售和短时货物储…

如何利用生成式AI创建图像和可视化效果

每个小型出版商在创建博客文章或新闻文章的过程中&#xff0c;都有一个恐慌时刻&#xff1a; “我用什么做我的特色图片&#xff1f;” 广告公司和媒体公司都有创意总监、摄影师和艺术家随时为他们创作图片。但我们其他人怎么办呢&#xff1f; 我们中的一些人会不顾更好的判…

数据中心扩展之路:创新的数据中心布线解决方案

在不断发展的数据管理领域中&#xff0c;现代技术的迅猛发展既带来了机遇&#xff0c;也带来了挑战&#xff0c;尤其是对不断扩展的数据中心而言。随着这些基础设施的快速发展和转型&#xff0c;对高效可靠的数据中心布线解决方案的需求日益增长。本文将探讨飞速&#xff08;FS…

redis常见类型设置、获取键值的基础命令

redis常见类型设置、获取键值的基础命令 获取键值的数据类型 命令&#xff1a;TYPE keyname 常见数据类型设置、获取键值的基本命令 string类型 置键值&#xff1a;set keyname valuename获取键值&#xff1a;get keyname删除&#xff1a; del keyname list类型 从左边向列表…

关于在Qlabel遮罩方面的踩坑实录

先看目标效果&#xff1a; 想要实现封面图标的遮罩效果&#xff0c;有两个思路&#xff1a; 一、在鼠标移动到这个item上面时&#xff0c;重新绘制pixmap 例如以下代码&#xff1a; #include <QApplication> #include <QWidget> #include <QPixmap> #incl…

马尔科夫蒙特卡洛_吉布斯抽样算法(Markov Chain Monte Carlo(MCMC)_Gibbs Sampling)

定义 输入:目标概率分布的密度函数 p ( x ) p(x) p(x),函数 f ( x ) f(x) f(x) 输出: p ( x ) p(x) p(x)的随机样本 x m 1 , x m 2 , ⋯ , x n x_{m1},x_{m2},\cdots,x_n xm1​,xm2​,⋯,xn​,函数样本均值 f m n f_{mn} fmn​; 参数:收敛步数 m m m,迭代步数 n n n。 (1)初…

camtasia2024绿色免费安装包win+mac下载含2024最新激活密钥

Hey, hey, hey&#xff01;亲爱的各位小伙伴&#xff0c;今天我要给大家带来的是Camtasia2024中文版本&#xff0c;这款软件简直是视频制作爱好者的福音啊&#xff01; camtasia2024绿色免费安装包winmac下载&#xff0c;点击链接即可保存。 先说说这个版本新加的功能吧&#…