【Linux】Linux任务管理与守护进程

Linux任务管理与守护进程

  • 一、任务管理
    • 1、进程组概念
    • 2、作业概念
    • 3、会话概念
    • 4、相关操作
  • 二、守护进程
    • 1、守护进程的创建
    • 2、守护进程的库函数

一、任务管理


1、进程组概念

Linux中,每个进程除了有一个进程ID之外,还有一个属性是进程组(PGID),进程组是一个或多个进程的集合

通常,进程组内的所有进程它们与同一作业(任务)相关联,可以接收来自同一终端的各种消息和信号。每个进程组有一个唯一的进程组ID。每个进程组都可以有一个组长进程。组长进程的标识是:其进程组ID等于其进程ID,组长进程可以创建一个进程组,创建该组中的进程。

需要注意的是,只要在某个进程组中有一个进程存在,则该进程组就存在,这与其组长进程是否终止无关,也就是说: 进程组的生命周期从被创建开始,到其内所有进程终止或离开该组

2、作业概念

Shell区分前后台不是按照进程来区分的,而是按照作业(Job)或者进程组(Process Group)。

一个前台作业可以由多个进程组成,一个后台作业也可以由多个进程组成,Shell可以运行一个前台作业和任意多个后台作业,这称为作业控制。

作业与进程组的区别
如果作业中的某个进程又创建了子进程,则子进程不属于作业。一旦作业运行结束,Shell就把自己提到前台(Shell也是一个作业,当其他前台作业在运行时,Shell就会变成后台作业,这就是为什么我们完成其他作业时,无法使用Shell),如果原来的前台进程还存在,也就是这个被创建的子进程还没有终止,那么它将自动变为后台进程组。

3、会话概念

Linux是多用户多任务的分时系统,所以必须要支持多个用户同时使用一个操作系统。当一个用户登录一次系统就形成一次会话,一个会话可包含多个进程组,但只能有一个前台进程组。每个会话都有一个会话首领(leader),即创建会话的进程。


Linux给我们提供了一个系统调用:setsid()调用此函数能创建一个会话。

  • 必须注意的是,只有当前进程不是进程组的组长时,才能创建一个新的会话。调用setsid之后,调用此函数的进程成为新会话的leader。
  • 此函数的返回值是:成功则返回调用进程的ID。当出现错误时,返回 -1,并设置errno来指示错误。

  • 一个会话可以有10个或控制终端(会话的领头进程打开一个终端之后, 该终端就成为该会话的控制终端),在这个会话中的所有进程组都关联这个终端文件。
  • 建立与控制终端连接的会话首进程又被称为控制进程。
  • 一个会话中的几个进程组可被分为一个前台进程组和多个后台进程组,所以一个会话中,应该包括控制进程(会话首进程),一个前台进程组和任意多个后台进程组。

在这里插入图片描述

例如,下面我们用运行多个sleep,让它们协同完成我们的任务,则它们应该属于同一个进程组,这些进程组的控制终端相同,它们同属于一个会话,当用户在控制终端输入特殊的控制键(如Ctrl+C产生SIGINT,Ctrl+\产生SIGQUIT,Ctrl+Z产生SIGTSTP),内核就会发送相应的信号给前台进程组中的所有进程。

在这里插入图片描述

我们看到了这个进程组的会话id是28977,我们来查看一下,这个会话首领是谁?

在这里插入图片描述

结果显示是bash,所以bash是当前会话的会话首领,也是控制进程。当我们用Xshell或是终端登录时,本质都是先创建一个会话,然后启动bash进程,该进程成为组长,所有的命令行启动的任务都是在对应的会话内运行的。

实际我们每一次登录的过程都是新建会话的过程,同一个会话中的所有进程的SID是相同的。

4、相关操作

前台进程&后台进程
直接运行某一可执行程序,此时默认将程序放到前台运行,在前台运行的进程的状态后有一个+号,例如S+

在这里插入图片描述

运行可执行程序时在后面加上&,可以指定将程序放到后台运行,在后台运行的进程的状态后没有+号。

在这里插入图片描述
我们将程序放到后台运行时会发现多了一行提示信息,例如上述的:

[1] 7560

其中[1]是作业的编号,如果同时运行多个作业可以用这个编号进行区分,7560是该作业中最后一个进程的id(一个作业可以由多个进程组成)。

jobs、fg、bg命令

使用jobs命令,可以查看当前会话当中有哪些作业。

在这里插入图片描述
使用fg命令(foreground),可以将某个作业提至前台运行,如果该作业正在后台运行则直接提至前台运行,如果该作业处于停止状态,则给进程组的每个进程发SIGCONT信号使它继续运行并提至前台。

例如,使用fg 1命令将1号作业提到前台运行

在这里插入图片描述
使用bg命令,可以让某个停止的作业在后台继续运行(Running),本质就是给该作业的进程组的每个进程发SIGCONT信号。

在这里插入图片描述

二、守护进程

守护进程也称精灵进程(Daemon),是运行在后台的一种特殊进程,它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。

守护进程是一种很有用的进程,Linux的大多数服务器就是用守护进程实现的,守护进程一般在系统启动时开始运行,除非强行终止,否则直到系统关机都保持运行。守护进程经常以超级用户(root)权限运行,因为它们要使用特殊的端口(1-1024)或访问某些特殊的资源。

用户登录时创建会话,当用户退出时销毁会话,会话销毁会话内的进程就有可能受到影响,因为我们的服务器进程是要一直运行的而且不能受用户登录和登出的影响,所以服务器要采用守护进程的方式运行!

1、守护进程的创建

守护进程创建的原理是:当我们运行一个服务器程序时,不要在当前用户登录的会话内运行服务器程序,而是创建一个新的会话(利用系统调用setsid()),让这个服务器程序在这个新的会话内运行,这样用户的登录与登出都不会影响我们服务器程序。
在这里插入图片描述

守护进程的创建步骤

  1. 设置文件掩码为0,(保证我们后续设置的权限不受权限掩码的影响)。
  2. 忽略异常信号,如:SIGCHLD SIGPIPE(避免不必要的信号干扰服务器的运行)。
  3. fork后终止父进程,子进程创建新会话(保证当前进程不是组长进程)。
  4. 再次fork,终止父进程,保持子进程不是会话首进程,从而保证后续不会再和其他终端相关联

守护进程不能直接和用户交互,也就没有必要再打开某个终端了,而打开一个终端需要你是会话首进程,为了防止守护进程打开终端,我们直接让父进程退出,由于子进程不是会话首进程,也就没有能力打开其他终端了。(这是一种防御性编程,该操作不是必须的)

  1. 更改工作目录为根目录(方便帮我们使用和查找文件)。
  2. 将标准输入、标准输出、标准错误重定向到/dev/null

守护进程不能直接和用户交互,也就是说守护进程已经与终端去关联了,因此一般我们会将守护进程的标准输入、标准输出以及标准错误都重定向到/dev/null/dev/null是一个字符文件(设备),通常用于屏蔽/丢弃输入输出信息。(该操作不是必须的)

从上面的操作中我们也能看出:守护进程本质是孤儿进程

#pragma once
#include <iostream>
#include <cstring>
#include <cerrno>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <fcntl.h>void Daemon()
{// 1. 将权限掩码设置为0umask(0);// 2.忽略SIGCHILD, SIGPIPE信号if (SIG_ERR == signal(SIGCHLD, SIG_IGN)){std::cerr << "signal fail: " << strerror(errno) << std::endl;exit(errno);}if (SIG_ERR == signal(SIGPIPE, SIG_IGN)){std::cerr << "signal fail: " << strerror(errno) << std::endl;exit(errno);}// 3. 创建子进程,建立新的会话pid_t id = fork();if (id < 0){std::cerr << "fork fail: " << strerror(errno) << std::endl;exit(errno);}else if (id > 0) exit(0); // 父进程退出if (setsid() < 0){std::cerr << "setsid fail: " << strerror(errno) << std::endl;exit(errno);}// 4.再次fork,终止父进程,保持子进程不是会话首进程,从而保证后续不会再和其他终端相关联if (fork() > 0) exit(0);// 5.更改工作目录if (chdir("/") < 0){std::cerr << "chdir fail: " << strerror(errno) << std::endl;exit(errno);}// 6.将输入输出重定向到/dev/nullint fd = open("/dev/null", O_RDWR);if (fd < 0){std::cerr << "open fail: " << strerror(errno) << std::endl;exit(errno);}if (dup2(fd, 0) < 0){std::cerr << "dup2 fail: " << strerror(errno) << std::endl;exit(errno);}if (dup2(fd, 1) < 0){std::cerr << "dup2 fail: " << strerror(errno) << std::endl;exit(errno);}if (dup2(fd, 2) < 0){std::cerr << "dup2 fail: " << strerror(errno) << std::endl;exit(errno);}// 关闭不需要的文件描述符close(fd);
}

将此代码加到我们的服务器的启动前,或者一个死循环的程序的运行前,运行程序,我们用ps命令查看该进程信息:

在这里插入图片描述

我们发现该进程的TPGID为-1,TTY显示的是?也就意味着该进程已经与终端去关联了。
其次,我们还可以看到该进程的PID与其PGID和SID是不同的,也就是说该进程既不是组长进程也不是会话首进程。
此外,我们还可以看到服务器进程的SID(6069)与bash进程的SID(就是上面的642)是不同的,即它们不属于同一个会话。

通过ls /proc/进程id -al命令,可以看到该进程的工作目录已经成功改为了根目录。

在这里插入图片描述
通过ls /proc/进程id/fd -al命令,可以看到该进程的标准输入、标准输出以及标准错误也成功重定向到了/dev/null

在这里插入图片描述

2、守护进程的库函数

C语言给我们实现了一个daemon函数用于创建守护进程
daemon函数的函数原型如下:

int daemon(int nochdir, int noclose);

参数说明:

  • 如果参数nochdir为0,则将守护进程的工作目录该为根目录,否则不做处理。
  • 如果参数noclose为0,则将守护进程的标准输入、标准输出以及标准错误重定向到/dev/null,否则不做处理。

运行实例:

#include <unistd.h>int main()
{daemon(0, 0);while (1);return 0;
}

在这里插入图片描述

调用daemon函数创建的守护进程与我们原生创建的守护进程差距不大。区别是:

  • daemon函数创建出来的守护进程,既是组长进程也是会话首进程。
  • daemon函数没有进行信号屏蔽。

在实际使用中我们更加倾向于自己写daemon函数,这样定制性更好一些。

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

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

相关文章

CAD迷你看图 mac v4.4.5

CAD迷你看图是一款小巧的DWG文件浏览小工具&#xff0c;支持AutoCAD DWG/DXF等常用图纸文件&#xff0c;可脱离AutoCAD快速浏览DWG图纸&#xff0c;并提供了平移、缩放、全屏等功能。该软件采用独特的云技术&#xff0c;根据不同DWG图纸的需要自动装载相应字体&#xff0c;解决…

木马文件检测系统 毕业设计 JAVA+Vue+SpringBoot+MySQL

项目编号&#xff1a;S041&#xff0c;源码已在 Bilibili 中上架&#xff0c;需要的朋友请自行下载。 https://gf.bilibili.com/item/detail/1104375029为了帮助小白入门 Java&#xff0c;博主录制了本项目配套的《项目手把手启动教程》&#xff0c;希望能给同学们带来帮助。 …

Linux网络编程:IP协议

目录 一. IP协议的功能 二. IP协议报头 2.1 IP报头的格式 2.2 IP报头各部分含义 三. IP报文的分片问题 3.1 什么是分片 3.2 分片的原理 3.3 合并报文 四. 网段划分 4.1 网络号和主机号 4.2 网络号和主机号的划分策略 4.3 特殊的IP地址 4.4 IP地址数量不足问题 五.…

「滚雪球学Java」:Java前序篇(章节汇总)

&#x1f3c6;本文收录于「滚雪球学Java」专栏&#xff0c;专业攻坚指数级提升&#xff0c;助你一臂之力&#xff0c;带你早日登顶&#x1f680;&#xff0c;欢迎大家关注&&收藏&#xff01;持续更新中&#xff0c;up&#xff01;up&#xff01;up&#xff01;&#xf…

竞赛选题 深度学习卷积神经网络垃圾分类系统 - 深度学习 神经网络 图像识别 垃圾分类 算法 小程序

文章目录 0 简介1 背景意义2 数据集3 数据探索4 数据增广(数据集补充)5 垃圾图像分类5.1 迁移学习5.1.1 什么是迁移学习&#xff1f;5.1.2 为什么要迁移学习&#xff1f; 5.2 模型选择5.3 训练环境5.3.1 硬件配置5.3.2 软件配置 5.4 训练过程5.5 模型分类效果(PC端) 6 构建垃圾…

文心一言 VS 讯飞星火 VS chatgpt (121)-- 算法导论10.4 2题

二、用go语言&#xff0c;给定一个n结点的二叉树&#xff0c;写出一个 O(n)时间的递归过程&#xff0c;将该树每个结点的关键字输出。 文心一言&#xff1a; 在Go语言中&#xff0c;你可以使用递归函数来遍历二叉树的所有节点&#xff0c;并输出每个节点的关键字。以下是一个…

OpenLayers入门,OpenLayers从vue的assets资源路径加载geojson文件并解析数据叠加到地图上,以加载世界各国边界为例

专栏目录: OpenLayers入门教程汇总目录 前言 本章以加载世界各国边界的GeoJSON格式数据为例,讲解如何使用OpenLayers从vue的assets资源路径加载geojson文件并解析数据叠加到地图上。 二、依赖和使用 "ol": "^6.15.1"使用npm安装依赖npm install ol@…

redis爆满导致数据丢失

记一则redis爆满导致数据丢失的一场事故 某功能上线后&#xff0c;发现出现问题&#xff0c;最后定位到了 redis. 由于存储的数据过多&#xff0c;导致阿里云4G大小的 redis 爆满&#xff0c;触发了回收策略。 于是临时扩容,运维同学当时未找到阿里云配置。 后面我用工具连接了…

【递归、搜索与回溯算法】第七节.257. 二叉树的所有路径和46. 全排列

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;递归、搜索与回溯算法 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01;&am…

人工智能的发展方向:探索智能未来的无限可能

原创 | 文 BFT机器人 人工智能&#xff0c;简称AI&#xff0c;是一门专注于研究计算机如何能像人类一样思考、学习和解决问题的科学。它的创造初衷是构建一个智能系统&#xff0c;能模仿、模拟甚至实现人工智能的各种功能和行为&#xff0c;随着科技的持续进步&#xff0c;人工…

低成本IC上岸攻略—IC设计网课白嫖篇

数字电路基础 清华大学 王红主讲&#xff1a;数字电子技术基础 西安电子科技大学 任爱锋主讲&#xff1a;数字电路与逻辑设计 模拟电路基础 上交大 郑益慧主讲&#xff1a;模拟电子技术基础 清华大学 华成英主讲&#xff1a;模拟电子技术基础 半导体物理&#xff1a; 西…

java--死循环与循环嵌套

1.死循环 可以一直执行下去的一种循环&#xff0c;如果没有干预不会停下来的 2.死循环的写法 3.循环嵌套 循环中又包含循环 4.循环嵌套的特点 外部循环每循环一次&#xff0c;内部循环会全部执行完一轮

【QT】对象树

一、QT对象树的概念 先来看一下 QObject 的构造函数&#xff1a; 通过帮助文档我们可以看到&#xff0c;QObject 的构造函数中会传入一个 Parent 父对象指针&#xff0c;children() 函数返回 QObjectList。即每一个 QObject 对象有且仅有一个父对象&#xff0c;但可以有很多个…

美颜SDK集成指南:为应用添加视频美颜功能

随着社交媒体和直播应用的兴起&#xff0c;视频美颜功能已成为用户追求的一项热门特性。用户希望能够在拍摄照片或进行实时视频直播时&#xff0c;使用美颜功能来增强其外观。为了满足这一需求&#xff0c;开发者可以考虑集成美颜SDK&#xff0c;为其应用增加这一吸引人的功能。…

uniapp接口请求api封装,规范化调用

封装规范和vue中的差不多&#xff0c;都是统一封装成一个request对象&#xff0c;然后在api.js里面调用。 先创建一个utils文件夹&#xff0c;然后里面创建一个request.js&#xff0c;代码如下&#xff1a; export const baseURL 基础url地址const request (options) > …

面试题:线程池执行的用户任务抛出异常会怎样?

文章目录 ThreadPoolExecutor.execute源码分析 ThreadPoolExecutor.submit源码分析 ScheduledThreadPoolExecutor.schedule源码分析 思考&#xff1a;ThreadPoolExecutor.execute发生异常时为什么要退出 ThreadPoolExecutor.execute 源码分析 看源码可以知道&#xff0c;Thre…

VScode连接的服务器上使用jupyter显示请选择内核源

问题复现 我实在VScode上用ssh-remote连接的服务器&#xff0c;想用.ipynb文件上写东西&#xff0c;结果窗口上方弹出一个输入框&#xff0c;“请键入以选择内核”&#xff1b; 在扩展里找到jupyter更新一下 之前左边的图标是灰色的&#xff0c;后来我下下载了新的版本&#…

Xcode自定义快捷键

一、新建脚本 1. 编写脚本 把脚本sh文件保存在安全的目录&#xff0c;不会被删除 我这里主要是两个常用的&#xff1a; 1.打开终端: xcode-terminal.sh #!/bin/shif [ -n "$XcodeProjectPath" ]; then open -a Terminal "$XcodeProjectPath"/.. elseo…

数据挖掘和大数据的区别

数据挖掘 一般用于对企业内部系统的数据库进行筛选、整合和分析。 操作对象是数据仓库&#xff0c;数据相对有规律&#xff0c;数据量较少。 大数据 一般指对互联网中杂乱无章的数据进行筛选、整合和分析。 操作对象一般是互联网的数据&#xff0c;数据无规律&#xff0c;…

“淘宝” 开放平台接口设计思路|开放平台接口接入流程教程

最近对接的开放平台有点多&#xff0c;像淘宝、京东、快手、抖音等电商平台的开放平台基本对接了个遍&#xff0c;什么是CRUD BODY也许就是这样的吧&#xff01;&#xff01;&#xff01; 虽然对接各大开放平台没啥技术含量&#xff0c;但咱也得学点东西不是&#xff0c;不能白…