进程间关系与进程守护

一、进程组

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、代码实现

cpp 复制代码
#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);
        }
    }
}
相关推荐
秋已杰爱20 分钟前
HTTP中的Cookie与Session
服务器·网络协议·http
code bean1 小时前
【C#基础】函数传参大总结
服务器·开发语言·c#
shelby_loo1 小时前
通过 Docker 部署 WordPress 服务器
服务器·docker·容器
Hqst_Kevin1 小时前
Hqst 品牌 H81801D 千兆 DIP 网络变压器在光猫收发器机顶盒中的应用
运维·服务器·网络·5g·网络安全·信息与通信·信号处理
前端-文龙刚1 小时前
小程序给对象赋值(双向绑定)方法之一
服务器·小程序·apache
阿赭ochre2 小时前
Linux环境变量&&进程地址空间
linux·服务器
honey ball2 小时前
仪表放大器AD620
运维·单片机·嵌入式硬件·物联网·学习
微尘82 小时前
C语言存储类型 auto,register,static,extern
服务器·c语言·开发语言·c++·后端
可儿·四系桜2 小时前
如何在多台Linux虚拟机上安装和配置Zookeeper集群
linux·服务器·zookeeper