进程间关系和守护进程

news2024/9/20 18:38:09

序言

 当我们使用指令 ps 查看进程的相关信息时,在以前我们只是关注该进程的 PID(该进程的标识符)PPID(其父进程的标识符) 以及 STAT(该进程的状态)
 那 PGIDSID 又是什么?有什么作用呢?


1. 进程组

1.1 什么是进程组?

 当我们启动程序执行相应的任务时,我们的任务可能只是创建了一个进程:

 1 #include <iostream>
   2 #include <unistd.h>
   3 
   4 int main()
   5 {
   6     while(1)
   7     {
   8         std::cout << "I am running, my pid is " << getpid() << std::endl;
   9         sleep(1);
  10     }
  11     return 0;
  12 }

我们使用指令 ps 查看进程信息:
在这里插入图片描述

在这里的 PGID 就是代表进程组,进程组的 idPID 保持一致。当我们的进程组只包含一个进程时,进程的 ID 等于其进程 ID

 那如果我们的任务包含多个进程呢?举个栗子:
在这里插入图片描述
当一个进程组包含多个进程时,进程组的 ID 和第一个创建的进程的 ID 保持一致。

 总结一下,进程组是一个或者多个进程的集合, 一个进程组可以包含多个进程

1.2 组长进程

 每一个进程组都包含一个组长进程,组长进程的 ID 就是该进程组的 ID。根据上面代码的举例,我们不难得出以下结论:

  • 当一个进程组只有一个进程时,该进程就是组长进程
  • 当一个进程组包含多个进程时,首先创建的进程为组长进程

一个进程组的生每周期取决于最后终止的进程而非是组长进程。


2. 会话

2.1 什么是会话

 会话可以看成是 一个或多个进程组的集合, 一个会话可以包含多个进程组。每一个会话也有一个会话 ID(SID)
 创建一个新的会话时可以简单理解为 创建终端文件和启动 bash 进程

  • 终端:终端是用户与操作系统进行交互的界面。
  • bashbashLinux上 最常用的 Shell 之一,Shell 是运行在终端上的程序,它提供了用户与操作系统交互的接口。

怎么来证明呢?现在我在 XShell 上只是启动一个会话,查看我们的终端文件和 bash 进程:
在这里插入图片描述
在这里插入图片描述

可以看到只存在一个终端文件和 bash 进程,那我们再创建一个回话呢:
在这里插入图片描述在这里插入图片描述
现在就变成了两个终端文件和两个 bash 进程。

 所以在每一次登录时,都会为我们自动建立一次会话。会话的 id 和第一个创建的进程的 id 保持一致,在大多数情况下都是我们的 bash,除非是我们手动创建的会话。

2.2 创建一个会话

 可以调用 setsid 函数来创建一个会话, 前提是 调用进程不能是一个进程组的组长。
 大家都知道可以使用 ctrl + c 来终止当前程序(需要是前台的程序,后面会说)的执行吧,但是该程序必须是当前会话下的程序。那不是废话吗,我在我会话下启动的程序肯定就是啊,难不成跑到别处去了?
 没认识 setsid 之前你的话是对的,但是认识之后就不一定了,举个栗子:

   1 #include <iostream>
   2 #include <unistd.h>
   3 
   4 int main()
   5 {
   6     // child
   7     if(fork() ==  0)
   8     {
   			 // 创建新的会话
   9         setsid();
  10         while(1)
  11         {
  12             std::cout << "I am child process, my pid is " << getpid() << std::endl;
  13             sleep(2);
  14         }
  15     }
  16     // parent
  17     else
  18     {
  19         while(1)
  20         {
  21             std::cout << "I am parent process, my pid is " << getpid() << std::endl;
  22             sleep(2);
  23          }
  24     }
  25 
  26     return 0;
  27 }

现在我们运行这段程序:
在这里插入图片描述
程序正常运行,但是终止进程后子进程依然执行,这是因为子进程属于其他会话,不归当前会话管。那除了重启大法没办法终止他了吗?肯定不是,我们还有 kill 指令。


3. 前后台任务

3.1 前台任务

 前台任务会占据终端的输入输出,即它会接收你通过键盘输入的命令或数据,并将它的输出结果直接显示在终端上。前台任务会阻塞终端,直到它完成或者被你明确地放到后台执行。简而言之,前台任务会占有终端文件! 比如:

   1 #include <iostream>
   2 #include <unistd.h>
   3 
   4 int main()
   5 {
   6     while(true) sleep(1);
   7     return 0;
   8 } 

现在我们运行该程序,并向终端输入指令:
在这里插入图片描述
可以看到并没有任何结果,这是因为我们输入的指令都是被 bash 指令接受之后创建子进程执行的,但是现在终端文件被该进程占有了,自然 bash 收不到了。

3.2 后台任务

 后台任务是指那些在终端之外运行的任务,它们 不会直接占据终端的输入输出。后台任务可以在你执行其他任务或关闭终端时继续运行。要将一个任务放到后台执行,你可以在命令的末尾加上 & 符号。
 还是上一段程序,但是在运行时在最后加上 &:
在这里插入图片描述

可以看到,我们指令的执行并没有受到干扰。

 那我怎么查看我后台任务的执行情况呢,使用指令 jobs [-l]:
在这里插入图片描述

3.3 后台任务切回前台

 只需要使用指令 fg nn 代表该任务的编号:
在这里插入图片描述

3.4 前台任务切回后台

 首先我们需要使用指令 ctrl + z 将该任务暂停,之后使用指令 bg n 将该任务切换到后台:
在这里插入图片描述


4. 守护进程

 我们运行一个普通的进程时,不管是前台还是后台,当我们一退出,会话一结束。我们执行的进程也会随之终止,但是在很多应用场景下,服务是不能停的!不可能程序员一下班,我们的应用就罢工了吧!
 所以有了守护进程,守护进程通常用于 提供需要持续运行的服务,如网络服务(Web服务器、FTP服务器等)、数据库服务等。这些服务在系统运行期间 一直保持运行状态,确保用户可以随时访问。
 那我们如何创建一个守护进程呢,关键是 创建一个新的会话,当我们的会话结束时,该会话不受影响!但是只是靠一个进程是做不到的,因为 调用 setsid 的函数不能是进程组长!包含一个进程的进程组,该进程就是组长!解决方法也很简单,一个进程不行那就创建一个子进程嘛,创建的过程如下:

#pragma once

#include <unistd.h>
#include <signal.h>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

void Daemon(const std::string &newpath = "")
{
    // 防止一些异常退出信号
    signal(SIGCHLD, SIG_IGN);

    // 创建子进程,父进程退出
    if (fork() > 0)
        exit(0);

    // 设置一个新的会话
    setsid();

    // 关闭原来的文件描述符
    int fd = open("/dev/null", O_RDWR);
    if (fd > 0)
    {
        dup2(fd, 0);
        dup2(fd, 1);
        dup2(fd, 2);
        close(fd);
    }

    // 是否更改工作路径
    if (!newpath.empty())
    {
        chdir(newpath.c_str());
    }
}

 父进程的作用就是创建一个子进程,之后父进程的生命周期就结束了。子进程创建了一个新的会话,脱离了原来的会话。
 在这里为什么需要关闭原来的文件描述符呢?这是因为现有的文件描述符还指向原来会话的文件,这是不严谨的,因为我们当前已经脱离了原来的会话。在这里没有直接的关闭,因为 考虑到后续场景可能使用到读写操作。所以我们让他指向一个空的文件(类似于空指针)。是否需要切换路径和使用场景相关。


5. 总结

 在这篇文章中,我们介绍了进程的组以及会话的概念,还实现了一下守护进程功能的函数。

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

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

相关文章

最强神器Typora 2024(亲测有效)| Markdown 工具推荐

听俺讲一下 大家好&#xff0c;我是程序员-杨胡广&#xff0c;今天想给大家分享一个在编写文档时的神器——Typora。相信不少小伙伴都在寻找一款既简洁又强大的 Markdown 编辑工具&#xff0c;而 Typora 无疑是最值得推荐的选择。 当我在大学时偶然发现了它&#xff0c;直到今…

【Python 数据分析学习】Matplotlib 的基础和应用

题目 1 Matplotlib 主要特性2 Matplotlib 基础知识2.1 导入模块2.2 图形构成2.2.1 图形&#xff08;Figure&#xff09;2.2.2 轴 &#xff08;Axes&#xff09;2.2.3 轴线&#xff08;axis&#xff09; 2.5 中文设置2.5.1 借助rcParams修改字体实现设置2.5.2 增加一个fontprope…

计算机视觉 对比学习 串烧二

文章目录 文章列表三、CPC3.1 文章摘要3.2 实验结果3.3 文章图示图 1: 对比预测编码&#xff08;CPC&#xff09;的概览图 2: 语音&#xff08;演讲&#xff09;表示的t-SNE可视化图 3: 预测未来潜在表示的准确率图 4: 图像的对比预测编码&#xff08;CPC&#xff09;的可视化图…

【Qt】Qt C++ Widget中嵌入qml

1. 效果 2. 方法 使用QQuickWidget方式 QQuickWidget *view new QQuickWidget;view->setSource(QUrl::fromLocalFile("myqmlfile.qml"));view->show();除了QQuickWidget方式还可以使用QQuickView方式&#xff0c;请自行查阅资料 3. 代码 3.1 工程目录 3.2 …

初始爬虫7

针对数据提取的项目实战&#xff1a; 补充初始爬虫6的一个知识点&#xff1a; etree.tostring能够自动补全html缺失的标签&#xff0c;显示原始的HTML结构 # -*- coding: utf-8 -*- from lxml import etreetext <div> <ul> <li class"item-1">…

图论篇--代码随想录算法训练营第五十八天打卡|拓扑排序,dijkstra(朴素版),dijkstra(堆优化版)精讲

拓扑排序 题目链接&#xff1a;117. 软件构建 题目描述&#xff1a; 某个大型软件项目的构建系统拥有 N 个文件&#xff0c;文件编号从 0 到 N - 1&#xff0c;在这些文件中&#xff0c;某些文件依赖于其他文件的内容&#xff0c;这意味着如果文件 A 依赖于文件 B&#xff0…

软件设计之JavaWeb(4)

软件设计之JavaWeb(4) 此篇应在MySQL之后进行学习: 路线图推荐&#xff1a; 【Java学习路线-极速版】【Java架构师技术图谱】 尚硅谷全新JavaWeb教程&#xff0c;企业主流javaweb技术栈 资料可以去尚硅谷官网免费领取 此章节最好学完JDBC观看 学习内容&#xff1a; 会话管理…

CleanClip for Mac 剪切板 粘贴工具 历史记录 安装(保姆级教程,新手小白轻松上手)

CleanClip&#xff1a;革新macOS剪贴板管理体验 目录 功能概览 多格式历史记录保存智能搜索功能快速复制操作拖拽功能 安装指南 前期准备安装步骤 配置与使用 功能概览 多格式历史记录保存 CleanClip支持保存文本、图片、文件等多种格式的复制历史记录&#xff0c;为用户提…

vue 在线预览word和excel

yarn add vue-office/excel vue-office/docx <template><div><vue-office-docx:src"docx"style"height: 100%; margin: 0; padding: 0"rendered"rendered"/></div> </template><script> //引入VueOfficeDoc…

C:字符串函数(续)-学习笔记

穗 一些闲话&#xff1a; 最近玩了这款饿殍-明末千里行&#xff0c;不知大家是否有听过这款游戏&#xff0c;颇有感触&#xff01;&#xff01;&#xff01; 游戏中最让我难以忘怀的便是饿殍穗线的故事&#xff0c;生在如今时代的我之前无法理解杜甫在目睹人间悲剧时的心情&…

低级编程语言和高级编程语言

一.区分低级编程语言和高级编程语言的方法 1.低级编程语言 低级编程语言,并不是简单的编程语言,而是写起来很费事的编程语言,如所有编程语言的"祖宗":汇编语言,写起来极其麻烦,说不定一个 int a1; 它就得写好几行,甚至十几行 这样麻烦的编程语言为什么还没消失那,因…

蓝桥杯省赛真题——大臣的旅费

输入样例&#xff1a; 5 1 2 2 1 3 1 2 4 5 2 5 4 输出样例&#xff1a; 135分析&#xff1a; 本题实际上要求我们去求在图中最远两点之间的距离&#xff0c;也就是树的直径 我们先从某一个点出发&#xff0c;到达离其最远的点&#xff0c;然后再重复操作一次即可 #inclu…

1184. 公交站间的距离(24.9.16)

题目 环形公交路线上有n个站&#xff0c;按次序从 0 到n - 1进行编号。已知每一对相邻公交站之间的距离&#xff0c;distance[i]表示编号为i的车站和编号为(i 1) % n的车站之间的距离。环线上的公交车都可以按顺时针和逆时针的方向行驶。要求返回乘客从出发点start到目的地de…

C++11(3)

目录 可变参数模版 获取参数包值的方式 1.递归方式展开参数包 2.使用数组逗号表达式展开 emplace_back函数 lambda表达式 C98中的例子 lambda表达式 语法 lambda表达式和函数比较 包装器 function包装器 bind绑定器 可变参数模版 C11 的新特性可变参数模板能够让您…

Java--String类

前言&#xff1a; 在之前的学习中&#xff0c;学习了和了解了一些类的基本使用&#xff0c;例如object类等等&#xff0c;但是我们用String这个引用或者说这个类其实我们已经用了好久&#xff0c;只不过没有具体分析过&#xff01; 对于String类&#xff0c;它可以引用一个字符…

VTD激光雷达(1)——01_OptiX_RayTracing-笔记

文章目录 前言一、文档介绍1、 总结 前言 不想学习怎么办 感谢VTD官方视频指导 一、文档介绍 1、 1 2 站在光的角度上考虑问题&#xff0c;如果用光源发出的&#xff0c;好多没到传感器上&#xff0c;这样会导致计算量很大&#xff0c;我们用传感器的trace 3 4 5 6 7 8 …

如何在 Vue 3 + Element Plus 项目中实现动态设置主题色以及深色模式切换

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、引言二、项目依赖和环境配置1. VueUse2. use-element-plus-theme3. 安装依赖 三、实现深色模式切换1. 设置深色模式状态2. 模板中的深色模式切换按钮3. 深色模式的效果展示 四、动态切换主题色五、总结 一、引言 在现代…

平安养老险阜阳中心支公司开展金融教育宣传专项活动

为全面深入开展“金融教育宣传月”的各项工作&#xff0c;不断完善金融惠民利民举措&#xff0c;提升金融服务质效&#xff0c;帮助基层群众增强维权意识、防非反诈的自我保护能力。近日&#xff0c;平安养老保险股份有限公司&#xff08;以下“平安养老险”&#xff09;阜阳中…

神经网络_使用tensorflow对fashion mnist衣服数据集分类

from tensorflow import keras import matplotlib.pyplot as plt1.数据预处理 1.1 下载数据集 fashion_mnist keras.datasets.fashion_mnist #下载 fashion mnist数据集 (train_images, train_labels),(test_images, test_labels) fashion_mnist.load_data()print("t…

食品包装识别系统源码分享

食品包装识别检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…