进程组


什么是进程组


之前我们提到了进程的概念, 其实每一个进程除了有一个进程 ID(PID)之外 还属于一个进程组。进程组是一个或者多个进程的集合, 一个进程组可以包含多个进程。 每一个进程组也有一个唯一的进程组 ID(PGID), 并且这个 PGID 类似于进程 ID, 同样是一个正整数, 可以存放在 pid_t 数据类型中。

C++
$ ps -eo pid,pgid,ppid,comm | grep test
#结果如下
PID  PGID  PPID  COMMAND
2830 2830  2259  test
# -e 选项表示 every 的意思, 表示输出每一个进程信息
# -o 选项以逗号操作符(,)作为定界符, 可以指定要输出的列

组长进程


每一个进程组都有一个组长进程。 组长进程的 ID 等于其进程 ID。我们可以通过 ps 命
令看到组长进程的现象:

Shell
[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 两个进程。进程组组长的作用: 进程组组长可以创建一个进程组或者创建该组中的进程进程组的生命周期: 从进程组创建开始到其中最后一个进程离开为止。注意:主要某个进程组中有一个进程存在, 则该进程组就存在, 这与其组长进程是否已经终止无关

会话


什么是会话


刚刚我们谈到了进程组的概念, 那么会话又是什么呢? 会话其实和进程组息息相关,
会话可以看成是一个或多个进程组的集合, 一个会话可以包含多个进程组。每一个会
话也有一个会话 ID(SID)

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

Shell
[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 字段相关的进程

从结果来看 3 个进程对应的 PGID 相同, 即属于同一个进程组。

如何创建会话

可以调用 setseid 函数来创建一个会话, 前提是调用进程不能是一个进程组的组长。

#include <unistd.h>
/*
*功能:创建会话
*返回值:创建成功返回 SID, 失败返回-1
*/
pid_t setsid(void);

该接口调用之后会发生:调用进程会变成新会话的会话首进程。此时, 新会话中只有唯一的一个进程,调用进程会变成进程组组长。 新进程组 ID 就是当前调用进程 ID,该进程没有控制终端。 如果在调用 setsid 之前该进程存在控制终端, 则调用之后会切断联系

需要注意的是: 这个接口如果调用进程原来是进程组组长, 则会报错, 为了避免这种情况, 我们通常的使用方法是先调用 fork 创建子进程, 父进程终止, 子进程继续执行, 因为子进程会继承父进程的进程组 ID, 而进程 ID 则是新分配的, 就不会出现错误的情况。

会话 ID(SID)


上边我们提到了会话 ID, 那么会话 ID 是什么呢? 我们可以先说一下会话首进程, 会话首进程是具有唯一进程 ID 的单个进程, 那么我们可以将会话首进程的进程 ID 当做是会话 ID。注意:会话 ID 在有些地方也被称为 会话首进程的进程组 ID, 因为会话首进程总是一个进程组的组长进程, 所以两者是等价的。

控制终端


先说一下什么是控制终端?

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

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

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

守护进程

上篇博客写了TCP,将服务器守护进程化

其余内容不变,只修改main.cc和引入封装Daemon.hpp

Daemon.hpp

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

main.cc

#include"TcpServer.hpp"
#include <memory>
#include "Protocol.hpp"
#include"NetCal.hpp"
#include "Daemon.hpp"
void Usage(std::string proc)
{std::cerr<<"Usage: "<<proc<<"prot"<<std::endl;
}//  ./tcpserver 
int main(int argc,char* argv[])
{if(argc !=2){Usage(argv[0]);exit(USAGE_ERR);}Daemon(false, false);//1.顶层std::unique_ptr<Cal> cal = std::make_unique<Cal>();//2.协议层std::unique_ptr<Protocol> protocol = std::make_unique<Protocol>([&cal](Request &req)->Response{return cal->Execute(req);});//3.服务器层std::unique_ptr<TcpServer> tsvr = std::make_unique<TcpServer>(std::stoi(argv[1]),[&protocol](std::shared_ptr<Socket>&sock,InetAddr &client){protocol->GetReqquest(sock,client);});tsvr->Start();return 0;
}

此时将服务器放在后台进程里键盘输入的任何消息只会发送给前台进程接收

 也可以调用系统调用

deamon

 

#include"TcpServer.hpp"
#include <memory>
#include "Protocol.hpp"
#include"NetCal.hpp"
#include "Daemon.hpp"#include <unistd.h>
void Usage(std::string proc)
{std::cerr<<"Usage: "<<proc<<"prot"<<std::endl;
}//  ./tcpserver 
int main(int argc,char* argv[])
{if(argc !=2){Usage(argv[0]);exit(USAGE_ERR);}daemon(0, 0);//1.顶层std::unique_ptr<Cal> cal = std::make_unique<Cal>();//2.协议层std::unique_ptr<Protocol> protocol = std::make_unique<Protocol>([&cal](Request &req)->Response{return cal->Execute(req);});//3.服务器层std::unique_ptr<TcpServer> tsvr = std::make_unique<TcpServer>(std::stoi(argv[1]),[&protocol](std::shared_ptr<Socket>&sock,InetAddr &client){protocol->GetReqquest(sock,client);});tsvr->Start();return 0;
}

效果也是一样的

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【跟着PMP学习项目管理】项目管理 之 范围管理知识点

目录 一、收集需求 1、知识点汇总 2、输入 3、工具 4、输出 二、定义范围 1、知识点汇总 2、输入 3、工具 4、输出 三、创作工作分解结构 1、知识点汇总 2、输入 3、工具 4、输出 四、核实范围 1、知识点汇总 2、输入 3、工具 4、输出 五、控制范围 1、知…

AIX 环境磁盘空间管理指南

AIX 环境磁盘空间管理指南 在AIX环境中&#xff0c;磁盘空间的监控、管理与扩展是运维人员必备的技能。本文通过实际案例&#xff0c;系统地介绍如何查询磁盘信息、卷组(VG)、逻辑卷(LV)信息&#xff0c;以及在磁盘空间不足时的扩容方案&#xff0c;帮助读者掌握磁盘空间管理的…

k8s将service的IP对应的不同端口分配到不同的pod上

在Kubernetes中&#xff0c;Service是一种抽象层&#xff0c;它将请求路由到一组Pod。当你需要将Service的不同端口映射到不同的Pod时&#xff0c;可以通过以下两种主要方式实现&#xff1a; 方法一&#xff1a;使用单个Service的多端口配置 如果不同的Pod提供不同的服务&…

aic8800M40低功耗sdio wifi在arm-linux平台调试经验

背景 好多年没有搞过wifi相关的内容了,最近也被安排上了,把一颗低功耗aic8800M40的芯片在arm-linux开发板上做bring up,记录一下SDIO wifi调试的过程和经验,SDIO驱动这里需要改动一些linux内核HOST驱动代码,会在文章中贴出来: AIC8800M40芯片简介 这个wifi芯片是一颗低…

Redis基础(1):NoSQL认识

SQL和NoSQL数据库可以分为关系型数据库和非关系型数据库&#xff0c;SQL(Structured Query Language)相信大家并不陌生&#xff0c;这是用于操作关系型数据库的语言&#xff0c;而NoSQL&#xff0c;顾名思义&#xff0c;它对应的就是非关系数据库&#xff0c;它是操作非关系型数…

QT6 源(153)模型视图架构里的表格窗体视图 QTableWidget 篇三:源码及其元素 QTableWidgetItem 的源代码带注释

&#xff08;14&#xff09;本源代码定义于头文件 qtablewidget . h 头文件 &#xff1a; #ifndef QTABLEWIDGET_H #define QTABLEWIDGET_H#include <QtWidgets/qtableview.h> #include <QtWidgets/qtwidgetsglobal.h> #include <QtCore/qlist.h> #include …

SSL证书是网络安全的一把利刃

SSL证书&#xff08;安全套接层证书&#xff0c;现普遍升级为TLS证书&#xff09;确实是网络安全领域中一把至关重要的“利刃”&#xff0c;它在保护数据传输安全、建立用户信任、防范网络攻击等方面发挥着不可替代的作用。以下是其核心价值与作用的详细分析&#xff1a;一、SS…

Apache 配置文件提权的实战思考

在 Linux 系统中&#xff0c;如果普通用户被授予以 sudo 执行 Apache 并加载自定义配置文件的权限&#xff08;如 sudo apache2 -f /home/user/user.conf&#xff09;&#xff0c;那么该权限极可能被滥用为本地提权路径。 虽然 Apache 默认采用了更严格的权限限制机制&#xff…

代码随想录算法训练营第四十四天|动态规划part11

1143.最长公共子序列 题目链接&#xff1a;1143. 最长公共子序列 - 力扣&#xff08;LeetCode&#xff09; 文章讲解:代码随想录 思路&#xff1a; 其实就是求两个字符串的最长公共子序列的长度 与公共子数组的区别是可以不连续 &#xff0c;顺序对就可以 状态转移方程不一样 …

部署mysql

# 环境: 操作系统window11 安装了vagrant 通过vagrant部署、启动虚拟机(centos7) # 准备安装mysql8 # 添加 MySQL 官方 YUM 源 sudo rpm -Uvh https://dev.mysql.com/get/mysql80-community-release-el7-7.noarch.rpm # 安装 MySQL Server sudo yum install -y mysql-s…

SQL分析与打印-p6spy组件

有性能消耗&#xff0c;只推荐在非生产环境下使用 SpringBoot3MybatisPlushttps://baomidou.com/guides/p6spy/ MyBatis-Plus提供了SQL分析与打印的功能&#xff0c;通过集成p6spy组件&#xff0c;可以方便地输出SQL语句及其执行时长。本功能适用于MyBatis-Plus 3.1.0及以上版本…

FLUX.1-Kontext 高效训练 LoRA:释放大语言模型定制化潜能的完整指南

在人工智能领域&#xff0c;尤其是大型语言模型&#xff08;LLM&#xff09;的应用浪潮中&#xff0c;高效、低成本地定制模型行为已成为关键需求。LoRA&#xff08;Low-Rank Adaptation&#xff09;技术以其参数高效、资源节省的特性脱颖而出。而 FLUX.1-Kontext 作为一款创新…

群晖 DS3617xs DSM 6.1.7 解决 PhotoStation 安装失败问题 PHP7.0

群晖 DS3617xs DSM 6.1.7 解决 PhotoStation 安装失败问题 PHP7.0问题描述解决方案1. 准备所需文件2. 检查当前 PHP 版本3. 安装 PHP 版本5. 查询已安装好的套件6. 升级 PHP 版本7. 手动安装套件PhotoStation注意事项总结问题描述 在群晖 DS3617xs DSM 6.1.7-15284 版本中&…

pnpm 升级

pnpm 的安装源太多了&#xff0c;感觉系统变量都有引入顺序。 今天踩坑记录&#xff1a; pnpm &#xff0c;如果最初用npm 装的&#xff0c;可以用npm 升级&#xff1b; 如果最初用brew 装的&#xff0c;得用brew 升级&#xff1b; 如果最初是用corepack 装的得用corepack 升级…

[C#] WPF - 资源URI

一、组成 1、资源URI总共包括4个部分(当前程序集可以省略前3个)&#xff1a; ①&#xff1a;pack://application:,,, ②&#xff1a;/[程序集名称] ③&#xff1a;;Component ④&#xff1a;/[资源路径] 二、举例 项目结构如下图所示&#xff1a; 1、MainWindow.xaml 文件…

【Mysql系列】Mysql 多级隔离级别揭秘

目录 一、什么是隔离级别 1.1、为什么复合操作需要事务&#xff1f; 1.2、事务的 ACID 特性如何保障操作可靠性&#xff1f; 1.3、隔离性通过隔离级别来控制 二、为什么用多级隔离级别 2.1、事务并发执行时可能引发以下问题 2.1.1、脏读&#xff08;Dirty Read&#xff…

odoo17 警示: selection attribute will be ignored as the field is related

在 Odoo 17 中&#xff0c;当使用 related 字段时&#xff0c;直接在 fields.Selection 中指定选择列表会被忽略&#xff08;因为选择项会从关联字段继承&#xff09;。wtd_fuwlx fields.Selection(服务类型 , relatedwtd_id.fuwlx, storeTrue)遇到了一个警告&#xff0c;提示…

gemma-3n-E2B多模态模型使用案例:支持文本、图像、语音输入

参考&#xff1a; https://developers.googleblog.com/en/introducing-gemma-3n-developer-guide/下载&#xff1a; https://modelscope.cn/models/google/gemma-3n-E2B-it 模型下载 运行代码&#xff1a; https://github.com/huggingface/huggingface-gemma-recipes 微调&…

计算机网络实验——互联网安全实验

实验1. OSPF路由项欺骗攻击和防御实验一、实验目的验证路由器OSPF配置过程。验证OSPF建立动态路由项过程。验证OSPF路由项欺骗攻击过程。验证OSPF源端鉴别功能的配置过程。验证OSPF防路由项欺骗攻击功能的实现过程。二、实验任务使用自己的语言简述该实验原理。如图1所示的网络…

Pytorch中torch.where()函数详解和实战示例

torch.where() 是 PyTorch 中非常常用的一个函数&#xff0c;功能类似于 NumPy 的 where&#xff0c;用于条件筛选或三元选择操作。在深度学习训练、掩码操作、损失函数处理等场景中非常常见。一、基本语法 torch.where(condition, x, y)condition&#xff1a;一个布尔张量&…