进程间关系与进程守护

一、进程组

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);
        }
    }
}
相关推荐
嘟嘟Listing6 分钟前
设置jenkins时区记录
运维·jenkins
嘟嘟Listing7 分钟前
jenkins docker记录
java·运维·jenkins
伴野星辰8 分钟前
小乌龟TortoiseGit 安装和语言包选择
linux·运维·服务器
枫叶丹414 分钟前
【在Linux世界中追寻伟大的One Piece】多线程(一)
java·linux·运维
残念ing16 分钟前
【Linux】—简单实现一个shell(myshell)
linux·运维·服务器
明月心95223 分钟前
linux mount nfs开机自动挂载远程目录
linux·运维·服务器
Ray550529 分钟前
bridge-multicast-igmpsnooping
linux·服务器·网络
库库的里昂1 小时前
Linux系统Docker部署开源在线协作笔记Trilium Notes与远程访问详细教程
linux·运维·docker·开源
在下不上天1 小时前
flume-将日志采集到hdfs
大数据·linux·运维·hadoop·hdfs·flume
Mango0000002 小时前
香港站群服务器有助于提升网站在搜索引擎中的排名
运维·服务器·搜索引擎