Linux进阶篇——守护进程、进程树与进程资源限制详解

🐇明明跟你说过:个人主页

🏅个人专栏:《Linux :从菜鸟到飞鸟的逆袭》🏅

🔖行路有良友,便是天堂🔖

目录

一、守护进程

1、守护进程的概念

2、常见的Linux守护进程

3、创建自己的守护进程 

二、进程树与进程组

1、进程树的概念

2、进程组与回话

三、进程资源限制

1、资源限制的概念

2、使用ulimit命令设置资源限制

3、常见的资源限制类型


一、守护进程

1、守护进程的概念

在 Linux 和其他 Unix 类操作系统中,守护进程(Daemon)是一种在后台运行的进程,通常用于执行系统级的任务和服务。这些任务和服务通常是不需要直接与用户交互的。守护进程在系统启动时就开始运行,并在后台持续运行,直到系统关闭。

守护进程的特点

  1. 后台运行:守护进程在系统后台运行,不与任何用户直接交互。
  2. 系统级任务:执行系统级的任务,如处理网络请求、管理设备、执行计划任务等。
  3. 长期运行:通常在系统启动时启动,并在整个系统运行期间保持运行。
  4. 父进程为 init/systemd:守护进程通常是由 init 或 systemd 进程派生的,因此其父进程 ID(PPID)通常是 1。

2、常见的Linux守护进程

  1. sshd:SSH 服务守护进程,处理远程登录请求。
  2. cron:计划任务守护进程,定期执行预定的任务。
  3. httpd 或 nginx:Web 服务器守护进程,处理 HTTP 请求。
  4. systemd:系统和服务管理器,用于启动和管理系统进程。

3、创建自己的守护进程 

创建自己的守护进程可以在 Linux 环境中实现,过程涉及将进程从前台转移到后台,脱离终端控制并设置为独立运行。

创建守护进程的一般步骤

  1. 创建子进程:使用 fork() 创建一个子进程,并使父进程退出。
  2. 创建新的会话:使用 setsid() 创建一个新的会话,脱离控制终端。
  3. 忽略 SIGHUP 信号:防止进程在控制终端关闭时收到挂起信号。
  4. 再次创建子进程:使进程不再是会话领导,从而避免重新获得控制终端。
  5. 更改工作目录:将工作目录更改为根目录,避免阻止文件系统卸载。
  6. 重设文件权限掩码:将文件权限掩码设置为 0,确保进程创建文件权限不受限制。
  7. 关闭文件描述符:关闭标准输入、输出和错误,并将它们重定向到 /dev/null。

示例代码
以下是一个 C 语言示例,演示如何创建一个简单的守护进程:

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

void create_daemon() {
    pid_t pid;

    // 创建子进程
    pid = fork();

    if (pid < 0) {
        // fork 失败
        perror("fork failed");
        exit(EXIT_FAILURE);
    }

    if (pid > 0) {
        // 父进程退出
        exit(EXIT_SUCCESS);
    }

    // 创建新的会话并脱离控制终端
    if (setsid() < 0) {
        perror("setsid failed");
        exit(EXIT_FAILURE);
    }

    // 忽略 SIGHUP 信号
    signal(SIGHUP, SIG_IGN);

    // 再次 fork,使进程不再是会话领导
    pid = fork();

    if (pid < 0) {
        perror("fork failed");
        exit(EXIT_FAILURE);
    }

    if (pid > 0) {
        // 第一个子进程退出
        exit(EXIT_SUCCESS);
    }

    // 更改工作目录
    if (chdir("/") < 0) {
        perror("chdir failed");
        exit(EXIT_FAILURE);
    }

    // 重设文件权限掩码
    umask(0);

    // 关闭文件描述符
    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);

    // 将标准输入、输出和错误重定向到 /dev/null
    open("/dev/null", O_RDWR);
    dup(0);
    dup(0);
}

int main() {
    create_daemon();

    // 守护进程的主循环
    while (1) {
        // 执行守护进程任务
        sleep(30); // 示例任务:每 30 秒执行一次
    }

    return 0;
}


解释

  • fork():创建一个子进程。如果 fork 成功,父进程的返回值为子进程的 PID,子进程的返回值为 0。父进程退出,使子进程在后台运行。
  • setsid():创建一个新的会话,并使子进程成为该会话的领导进程,从而脱离控制终端。
  • signal(SIGHUP, SIG_IGN):忽略挂起信号,防止进程在控制终端关闭时退出。
  • 再次 fork():创建一个新的子进程,使其不再是会话领导,从而避免重新获得控制终端。
  • chdir("/"):将工作目录更改为根目录,避免阻止文件系统卸载。
  • umask(0):重设文件权限掩码,确保进程创建文件权限不受限制。
  • 关闭文件描述符:关闭标准输入、输出和错误,并将它们重定向到 /dev/null,避免守护进程使用这些文件描述符。

测试和管理守护进程
编译和运行:将上述代码保存为 daemon_example.c 并编译运行。

gcc daemon_example.c -o daemon_example
./daemon_example


查看进程:使用 ps 或 top 命令查看守护进程是否在运行。

ps -ef | grep daemon_example


停止进程:使用 kill 命令终止守护进程。

kill <PID>


通过以上步骤,可以创建和管理自己的守护进程,完成后台任务或服务。根据需要,守护进程的任务逻辑可以在主循环中进行定制和扩展。

  

二、进程树与进程组

1、进程树的概念

在 Linux 操作系统中,进程树(Process Tree)是一个由所有当前运行的进程及其父子关系构成的层次结构。每个进程都可能有一个父进程和零个或多个子进程。通过这种层次关系,可以了解进程的启动顺序以及它们之间的关系。

进程树的关键概念

  1. 根进程:系统的第一个进程是由内核启动的进程,在大多数现代 Linux 系统中,systemd(PID 1)是根进程。它负责启动其他所有系统进程。
  2. 父进程和子进程:每个进程都有一个父进程,父进程可以创建子进程。子进程继承父进程的某些属性,并在需要时进行独立操作。
  3. 进程ID (PID):每个进程在系统中都有一个唯一的标识号,称为进程ID (PID)。
  4. 父进程ID (PPID):每个进程都有一个父进程ID (PPID),标识该进程的父进程。
  5. 孤儿进程:如果父进程退出而子进程仍在运行,这些子进程就成为孤儿进程,init 或 systemd 会接管它们。
  6. 僵尸进程:当一个进程终止但其父进程尚未调用 wait() 函数来获取其终止状态信息时,该进程就成为僵尸进程。

查看进程树
可以使用多种命令查看 Linux 系统中的进程树。

使用 pstree 命令
pstree 命令以树状结构显示进程间的关系:

pstree

如果还未安装pstree,可以执行以下命令安装

[root@localhost ~]# yum install psmisc

  

  •   systemd 是系统的初始化进程,负责启动和管理其他所有进程。
  • NetworkManager 是网络管理器服务,负责管理网络连接。
  • dhclient 是 DHCP 客户端,用于获取 IP 地址。
  • VGAuthService 是 VMware 的虚拟化认证服务。
  • agetty 是用于虚拟控制台的终端管理器。
  • auditd 是 Linux 审计守护进程,用于监视系统的安全审计事件。
  • containerd 是 Docker 容器守护进程的一部分,用于管理容器生命周期。
  • crond 是 cron 定时任务守护进程,用于执行预定的任务。

 

2、进程组与回话

在Linux操作系统中,每个进程都与一个进程组和一个会话相关联。这些概念有助于管理和控制进程之间的关系以及它们与终端之间的交互。

进程组(Process Group)

  • 进程组是一组相关联的进程的集合,这些进程可以接收同一信号并共享一个终端。
  • 每个进程组都有一个唯一的进程组ID (PGID),由其成员的任何进程创建。
  • 进程组中的一个进程可以通过其进程组ID将信号发送给组中的所有其他进程。


会话(Session)

  • 会话是一组一个或多个进程组的集合,它们都共享同一个控制终端。
  • 每个会话都有一个唯一的会话ID (SID),由会话中的任何进程创建。
  • 每个会话都有一个控制终端,该终端是由会话的首领进程(通常是会话的第一个进程)打开的,当控制终端关闭时,会话中的所有进程都会收到 SIGHUP 信号。
  • 进程可以通过 setsid() 系统调用创建新会话。


进程组与会话的关系

  • 一个进程可以是一个进程组的成员,并且同时也是一个会话的首领。
  • 会话的首领进程通常是登录 shell。
  • 进程组通常在同一个会话中,但一个进程可以通过调用 setsid() 来创建一个新的会话,并在其中成为首领进程。


相关系统调用和命令

  • getpgrp():获取进程的进程组ID。
  • getpgid(pid):获取指定进程的进程组ID。
  • setpgid(pid, pgid):将指定进程移动到另一个进程组。
  • setsid():创建一个新的会话,并将调用进程设置为会话首领。
  • ps 命令的 -j 选项可以显示进程ID、进程组ID和会话ID。

三、进程资源限制

1、资源限制的概念

在Linux系统中,进程资源限制是一种管理策略,用于控制进程使用系统资源的上限。这种机制的主要目的是防止某个进程占用过多资源,从而影响其他进程的正常运行。进程资源限制可以包括多种资源类型,如CPU时间、内存、打开文件数等。

在Linux中,Resouce limit(资源限制)是指在一个进程的执行过程中,它所能得到的资源的限制,比如进程的core file的最大值、虚拟内存的最大值等。这些限制的大小可以直接影响进程的执行状况。

在资源限制中,有两个重要的概念:soft limit(软限制)和hard limit(硬限制)。soft limit是实际对进程进行限制的值,而hard limit则是soft limit的上限,也是内核所能支持的资源上限。例如,对于RLIMIT_NOFILE(一个进程能打开的最大文件数,内核默认是1024),soft limit最大也只能达到1024,而hard limit则可以是更大的值或者为unlimited(无限制)。

用户可以通过ulimit命令来查看和修改用户层面的系统资源限制。ulimit命令可以查看或设置由shell及shell启动的程序可使用的资源限制。ulimit -a命令可以显示当前的各种用户进程限制。

 

2、使用ulimit命令设置资源限制

ulimit 命令用于设置当前 shell 中进程的资源限制。它可以限制某些资源的硬限制(hard limit)和软限制(soft limit)。软限制是进程当前可以使用的资源量,而硬限制是操作系统允许的最大资源量。

1. 设置核心转储文件大小的软限制为无限制:

ulimit -c unlimited


这会将核心转储文件大小的软限制设置为无限制,允许生成任意大小的核心转储文件。

2. 设置同时打开的文件描述符数量的软限制为 1024:

ulimit -n 1024


这会将同时打开的文件描述符数量的软限制设置为 1024,限制了进程可以打开的文件数量。

3. 将软限制设置为与硬限制相同:

ulimit -H -c unlimited


这会将核心转储文件大小的软限制设置为与硬限制相同,即设置为无限制。

4. 设置同时打开的文件描述符数量的硬限制为 2048:

ulimit -H -n 2048


这会将同时打开的文件描述符数量的硬限制设置为 2048,是操作系统允许的最大值。

4. 显示当前 shell 中的所有资源限制:

ulimit -a


这会显示当前 shell 中所有资源的软限制和硬限制。

 

3、常见的资源限制类型

  1. CPU 时间:限制进程可以使用的 CPU 时间量。可以通过 ulimit -t 命令设置。
  2. 内存:限制进程可以使用的物理内存或虚拟内存量。可以通过 ulimit -v 命令设置。
  3. 文件描述符:限制进程可以打开的文件描述符数量。可以通过 ulimit -n 命令设置。
  4. 打开文件数:限制进程可以同时打开的文件数量。可以通过 ulimit -H -n 命令设置。
  5. 堆栈大小:限制进程堆栈的大小。可以通过 ulimit -s 命令设置。
  6. 进程数:限制用户可以拥有的进程数量。可以通过 ulimit -u 命令设置。
  7. 核心转储文件大小:限制核心转储文件的大小。可以通过 ulimit -c 命令设置。
  8. 虚拟内存大小:限制进程的虚拟内存大小。可以通过 ulimit -v 命令设置。

 

 💕💕💕每一次的分享都是一次成长的旅程,感谢您的陪伴和关注。希望这些关于Linux的文章能陪伴您走过技术的一段旅程,共同见证成长和进步!😺😺😺

🧨🧨🧨让我们一起在技术的海洋中探索前行,共同书写美好的未来!!!

  • 53
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明明跟你说过

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值