当前位置: 首页 > article >正文

进程间关系与进程守护

一、进程组

1、理解

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

2、举例

上图就是用管道创建了一个进程组。

我们可以用 ps ajx | head -1 && ps ajx | grep sleep,来查看指定的进程。
发现PGID是一样的2114632。

3、结论

PGID是进程组组长的PID,进程组组长可以创建一个进程组,也可以在自己的进程组里面创建新进程(父进程)
进程组的声明周期终止于最后一个进程退出,与组长无关。

二、会话

1、理解

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

如三个进程SID相同,说明组成的进程组在同一个会话中。

2、Linux会话结构

首先我们登录Linux之后,先有 bash 进程创建终端文件,此时 bash 不仅是进程组组长,bash 进程组还是会话组长,我们大部分的工作都是在 bash 创建的会话里面完成的。建立与控制终端连接的会话首进程是控制进程 bash。

3、结论

(1)在同一个会话中允许存在多个进程组。

(2)但是前台进程只有一个,后台进程可以有多个

例如我在前台启动一个进程组,输入指令 bash 由于在后台,就不会处理指令。

(3)前后台:前台可以从标准输入中获取数据。进程在启动时最后带上&就是后台进程

(4)无论何时,发送的中断信号只能给前台进程。

三、控制终端

UNIX 系统中, 用户通过终端登录系统后得到一个 Shell 进程,这个终端成为 Shell  进程的控制终端。控制终端是保存在 PCB 中的信息,我们知道 fork 进程会复制 PCB 中的信息,因此由 Shell 进程启动的其它进程的控制终端也是这个终端。 默认情况下 没有重定向,每个进程的标准输入、标准输出和标准错误都指向控制终端,进程从标准输入读也就是读用户的键盘输入,进程往标准输出或标准错误输出写也就是输出到显示器上。另外会话、进程组以及控制终端还有一些其他的关系:
一个会话可以有一个控制终端,通常会话首进程打开一个终端(终端设备或伪终端设备)后,该终端就成为该会话的控制终端。
建立与控制终端连接的会话首进程被称为控制进程
一个会话中的几个进程组可被分成一个前台进程组 以及一个或者多个 后台进 程组
如果一个会话有一个控制终端,则它有一个前台进程组,会话中的其他进程组则为后台进程组。
无论何时进入终端的中断键(ctrl+c )或退出键( ctrl+\ ),就会将中断信号发送给前台进程组的所有进程。
如果终端接口检测到调制解调器(或网络)已经断开,则将挂断信号发送给控制进程(会话首进程)。

四、作业与作业控制

1、理解

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

2、作业控制操作

jobs:查看作业。-p查看作业pid

关于默认作业:对于一个用户来说,只能有一个默认作业(+),同时也只能有一个即将成为默认作业的作业(-),当默认作业退出后,该作业会成为默认作业。
+ : 表示该作业号是默认作业
-:表示该作业即将成为默认作业
无符号: 表示其他作业

fg 作业号:把一个指定作业提到前台(接受用户输入的数据)

把作业放回后台:(1)作业暂停(ctrl z,也叫挂起)之后OS就会把作业放回后台。(2)bg 作业号:在后台启动作业

3、作业状态

4、举例

五、守护进程

1、理解

一个服务进程独立成为一个会话,就不会受原来会话的影响。

2、把进程变成守护进程

不是进程组组长调用函数 setsid 就可以把自己变成守护进程。调用的进程就会变成新会话的首进程,此时会话中只有一个进程,也是一个进程组的组长。

做法:父进程先 fork 子进程,父进程退出,子进程调用函数,由于子进程继承父进程的进程组id,进程id被重新分配,所以守护进程是孤儿进程。

这种进程已经不属于 bash 会话,只能用 kill 杀死进程。

3、代码实现

#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 = "/";
// 路径/dev/null 文件里面的数据不能被读取,相当于是被丢弃
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);
        }
    }
}

http://www.kler.cn/a/313688.html

相关文章:

  • 蓝桥杯每日真题 - 第7天
  • 「Py」Python基础篇 之 Python都可以做哪些自动化?
  • CommandLineParser 使用
  • ArcGIS Pro属性表乱码与字段名3个汉字解决方案大总结
  • 解决 Redis 报错:`(error) NOAUTH Authentication required`
  • Java学习--网络编程
  • 浅析OceanBase数据库的向量化执行引擎
  • CSS中如何实现鼠标悬停效果?
  • 数据结构:(牛客OR36)链表的回文结构
  • (笔记自用)LeetCode:快乐数
  • mysql时间戳格式化yyyy-mm-dd
  • kubeadm方式安装k8s+基础命令的使用
  • 二层、三层网络基本原理
  • 缓存技巧 · Spring Cache Caffeine 高性能缓存库
  • Github 2024-09-20 Java开源项目日报Top10
  • 【快手】前端校招一面
  • 深入理解Python中的时间表示:Unix时间点、毫秒和微秒,以及time模块
  • 9.7floodFill图像分割
  • 98-策略模式的理解
  • 蓝桥杯—STM32G431RBT6(ADC数模转换,从原理到应用)
  • C++第十一节课 new和delete
  • [Python可视化]数据可视化在医疗领域应用:提高诊断准确性和治疗效果
  • AI视觉算法盒是什么?如何智能化升级网络摄像机,守护全方位安全
  • 机器学习--AlexNet
  • 系统架构设计师:软件架构的演化和维护
  • 【AI视频】Runway:Gen-2 运镜详解