news 2026/9/10 21:07:24

Linux 之 【守护进程】(、jobs、fg、bg、setsid、/dev/null、deamon、守护进程与孤儿进程的比较)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux 之 【守护进程】(、jobs、fg、bg、setsid、/dev/null、deamon、守护进程与孤儿进程的比较)

目录

1.守护进程

1.1基本概念

&:启动后台任务

jobs:查看后台任务

fg:将后台任务切换到前台

bg:将挂起的任务恢复到后台运行

Ctrl + z:挂起当前前台任务

1.2守护进程化步骤

setsid

/dev/null

1.3守护进程vs孤儿进程

deamon

6.4Xshell的登录


1.守护进程

守护进程(Daemon)是在后台运行、自成会话且脱离终端控制的特殊进程,通常用于执行系统任务(如日志记录、网络服务、定时任务等)
Linux中的守护进程通常以d结尾(如sshd),这是一种命名惯例,以标识其为后台服务进程

1.1基本概念

  1. 会话(Session):用户登录后创建一个会话,包含一个或多个进程组
  2. 场景终端与会话的关系典型示例
    默认情况一个终端严格对应一个会话用户直接在终端中运行bash
    使用screen/tmux一个物理终端管理多个子会话(每个子会话关联独立伪终端)screen -S session1
    异常情况终端被抢占或误配置(罕见)系统错误导致终端关联混乱
  3. 进程组(Process Group):一组相关进程,组长为第一个进程
    每个任务(前后台)对应一个进程组
  4. 在一个会话中,任何时刻只能有一个前台进程组,但可以有多个后台进程组
  5. 前台/后台任务:前台进程组拥有终端控制权,可读取键盘输入
    后台进程组只能向终端输出,不能读输入
  6. 当多个任务(进程组)在同一个会话内启动时,它们的SID(Session ID)相同,且通常与创建该会话的Shell 进程(如bash)的 PID相同
  7. 在 Linux 中关闭 Xshell 或退出 bash 时,默认后台进程会因 SIGHUP 被终止,但可通过守护进程化(如用 nohup、disown、setsid 或 systemd/screen 管理)使其脱离终端控制,避免受用户登录/退出影响,实现持久运行

&:启动后台任务

在命令末尾添加&符号可以将任务放到后台执行

此时会立即返回命令提示符,允许用户继续输入其他命令

jobs:查看后台任务

功能:列出当前 Shell 会话中的后台任务(包括暂停和运行中的任务)

用法:jobs [选项]

常用选项

  • -l:显示任务的 PID(进程 ID)。
  • -p:仅显示任务的 PID。
  • -r:仅显示运行中的任务。
  • -s:仅显示暂停的任务。

  • [1]:任务编号(Job ID),用于 fg/bg 操作。
  • +:默认操作的任务(如直接输入 fg 会操作该任务)。
  • -:下一个默认操作的任务。
  • Running:任务正在运行。
  • Stopped:任务已挂起(如按 Ctrl+Z)

fg:将后台任务切换到前台

功能:将后台任务或挂起的任务恢复到前台运行

用法:fg [%任务编号]

如果不指定任务编号,默认操作+标记的任务

fg后面不加%也可以,但只能写数字,而且只在bash里比较稳妥

bg:将挂起的任务恢复到后台运行

功能:将暂停的任务(如Ctrl+Z挂起的任务)恢复到后台继续运行

用法:bg [%任务编号]

如果不指定任务编号,默认操作+标记的任务

bg后面不加%也可以,但只能写数字,而且只在bash里比较稳妥

Ctrl + z:挂起当前前台任务

功能:暂停当前正在前台运行的任务,并返回 Shell 交互界面

行为:任务被挂起(Stopped状态),可以通过bg恢复到后台运行,或fg恢复到前台继续运行

命令/快捷键作用
jobs查看后台任务列表
fg %n将任务n切换到前台
bg %n将挂起的任务n恢复到后台运行
Ctrl+Z挂起当前前台任务
kill %n终止任务n(通过 PID 也可用kill PID

1.2守护进程化步骤

  1. 忽略异常信号:如SIGPIPESIGHUP
  2. 创建独立会话:调用setsid()创建新会话,成为新会话首进程和新进程组组长。注意:进程组组长不能调用setsid,需先fork子进程,让子进程调用setsid
  3. 改变工作目录:通常改为根目录/,避免卸载文件系统时产生冲突
  4. 重定向标准输入/输出/错误:重定向到/dev/null,防止操作终端
  5. 可选:再次fork并退出父进程,确保进程不是会话首进程(会话首进程可能通过open("/dev/tty")重新关联终端)
#pragma once #include <iostream> #include <unistd.h> #include <cstdlib> #include <signal.h> #include <string> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> const std::string nullfile = "/dev/null"; void Daemon(const std::string& cwd = "/") // 默认切换到根目录 { // 1. 忽略常见信号(避免僵尸进程和管道写入错误) signal(SIGCHLD, SIG_IGN); // 忽略子进程退出信号 signal(SIGPIPE, SIG_IGN); // 忽略管道破裂信号 signal(SIGHUP, SIG_IGN); // 忽略终端挂断信号(关键!) // 2. 第一次 fork:脱离终端控制 pid_t pid = fork(); if (pid < 0) { std::cerr << "First fork failed!" << std::endl; exit(EXIT_FAILURE); } if (pid > 0) exit(EXIT_SUCCESS); // 父进程退出,子进程成为孤儿进程(被 init 领养) // 3. 创建新会话(脱离原会话和终端) if (setsid() < 0) { std::cerr << "setsid() failed!" << std::endl; exit(EXIT_FAILURE); } // 4. 第二次 fork:确保进程不是会话首进程(防止重新获取终端) pid = fork(); if (pid < 0) { std::cerr << "Second fork failed!" << std::endl; exit(EXIT_FAILURE); } if (pid > 0) exit(EXIT_SUCCESS); // 父进程退出 // 5. 更改工作目录(避免占用可卸载的文件系统) if (!cwd.empty()) { if (chdir(cwd.c_str()) < 0) { std::cerr << "chdir() to " << cwd << " failed!" << std::endl; exit(EXIT_FAILURE); } } // 6. 重定向标准输入/输出/错误到 /dev/null int fd = open(nullfile.c_str(), O_RDWR); if (fd < 0) { std::cerr << "open(/dev/null) failed!" << std::endl; exit(EXIT_FAILURE); } dup2(fd, STDIN_FILENO); // 标准输入 dup2(fd, STDOUT_FILENO); // 标准输出 dup2(fd, STDERR_FILENO); // 标准错误 close(fd); // 7. 可选:重置文件权限掩码 umask(0); }

进程脱离终端的核心方法是通过两次fork()结合setsid()创建独立会话,并主动放弃控制终端关联权限:首次fork()后父进程退出,子进程调用setsid()成为新会话首进程(脱离原终端),随后二次fork()使孙进程继承会话但不再是会话首进程(彻底丧失重新关联终端的权限),最后关闭或重定向标准文件描述符(stdin/stdout/stderr)至/dev/null,确保进程完全独立于终端运行,避免因终端关闭或用户信号被意外终止

setsid

类别详细说明
函数原型#include <unistd.h>
pid_t setsid(void);
所属系统Unix/Linux(POSIX 标准)
返回值

成功返回新会话ID,调用进程成为新会话首进程

失败返回 -1,并设置错误码

EPERM:调用进程已是进程组组长(需先调用 setpgid() 调整);

EACCES:进程缺乏权限(罕见,通常与终端权限相关)

头文件依赖<unistd.h>
功能描述
创建新会话调用进程成为新会话的会话首进程(Session Leader)
脱离原终端新会话没有控制终端(除非进程主动关联)
重置进程组调用进程成为新会话中的独立进程组组长(Process Group Leader)
隔离信号新会话中的进程不会收到原终端的信号(如SIGHUP
行为条件与结果
调用进程资格必须不是进程组组长(否则返回-1,错误码EPERM
典型调用场景子进程通过fork()创建后调用(确保非进程组组长)
对终端的影响原终端不再控制新会话,但新会话可主动关联其他终端

setsid() 强制要求调用者必须是非进程组组长,否则会因同一进程同时持有新旧两组组长身份而破坏进程组唯一性,导致信号传递、会话管理等关键操作出现结构混乱(如原进程组与新会话的归属冲突);调用成功后,新进程会脱离原会话并成为新会话和全新进程组的唯一组长,从而严格保证每个进程组和会话的层级独立性

/dev/null

类别详细说明
设备类型虚拟设备文件(字符设备,主设备号1,次设备号3
文件路径/dev/null
核心功能丢弃所有写入的数据,读取时返回EOF(文件结束符)
权限crw-rw-rw-(所有用户可读写)
底层实现内核中的空设备驱动,不存储任何数据,仅处理读写操作并立即返回
用途示例场景命令/代码示例
丢弃输出隐藏命令的冗余输出(如日志、调试信息)command > /dev/null(丢弃标准输出)
command 2> /dev/null(丢弃错误输出)
清空文件快速清空大文件内容(比> file更高效)cat /dev/null > file> file(后者更常用)
终止进程输入强制结束依赖输入的进程(如阻塞的read调用)command < /dev/null(进程会立即收到EOF并退出)
重定向错误分离标准输出和错误输出(仅保留错误)command > /dev/null 2>&1(丢弃所有输出)
command 2> /dev/null(仅丢弃错误)
脚本中的占位符作为无效输入源或输出目标,避免文件创建while read line < /dev/null; do ... done(循环立即结束)
特性说明
写入行为数据被内核直接丢弃,不占用磁盘空间或内存
读取行为立即返回EOF(文件结束符),无数据返回
性能影响极高效率(无 I/O 操作),适合高频重定向场景
/dev/zero区别/dev/zero返回空字符(\0),而/dev/null直接丢弃数据

1.3守护进程vs孤儿进程

特性守护进程(Daemon)孤儿进程(Orphan Process)
定义脱离终端控制、在后台独立运行的进程,通常由系统初始化脚本或用户手动启动父进程终止后,被init(或systemd)接管的子进程
创建方式主动通过fork()+setsid()+ 脱离终端等操作实现被动产生(父进程意外终止或主动退出)
会话控制主动调用setsid()创建新会话,成为会话首进程(Session Leader)通常仍属于原会话(除非显式调用setsid()
目的提供长期后台服务(如 Web 服务器、日志服务等)由系统自动回收,避免僵尸进程(除非子进程本身有问题)
终端关联完全脱离终端,不会因终端关闭而终止可能仍关联原终端(若未显式分离)
进程组通常成为独立进程组组长(通过setsid()进程组可能不变(除非父进程在退出前调整)

普通孤儿进程的生命周期由 init 管理,而守护进程主动控制自身行为(如重定向日志、监听端口等)

守护进程的独立性更强,而普通孤儿进程可能仍依赖原会话或进程组

deamon

项目说明
函数原型int daemon(int nochdir, int noclose);(定义于<unistd.h>,部分系统可能位于其他头文件)
功能将进程转换为守护进程(Daemon),封装了标准的守护进程化步骤(如脱离终端、切换目录、重定向文件描述符等),简化开发流程。
参数-nochdir:若为非零值,则不切换工作目录到根目录(/);若为 0,则切换。
-noclose:若为非零值,则不关闭/重定向标准文件描述符(stdin/stdout/stderr);若为 0,则将其重定向到/dev/null
返回值成功时返回0,失败时返回-1并设置errno(如权限不足、系统资源不足等)。
底层实现内部通常调用以下系统调用和操作:
1.fork()→ 创建子进程,父进程退出。
2.setsid()→ 脱离终端,创建新会话。
3.chdir("/")(若nochdir=0)。
4. 重定向stdin/stdout/stderr/dev/null(若noclose=0)。
使用场景- 需要快速实现守护进程化的场景。
- 避免手动编写重复的守护进程化代码。
- 适用于简单的后台服务程序。
注意事项1.非标准函数daemon()不是 POSIX 标准函数,部分系统(如某些嵌入式 Linux)可能不支持。
2.可移植性:若需跨平台,建议手动实现守护进程化步骤或使用条件编译。
3.日志记录:若需记录日志,应在调用daemon()前重定向文件描述符到日志文件,而非依赖默认的/dev/null
特性daemon()函数手动实现(系统调用组合)
开发效率高(一键调用,封装细节)低(需逐个调用系统调用并处理错误)
灵活性较低(参数有限,行为固定)高(可自定义目录切换、文件描述符处理等)
可移植性较低(非标准函数,依赖系统支持)较高(基于标准系统调用,跨平台兼容性强)
适用场景快速开发、简单守护进程复杂需求、需要精细控制的场景

1.4Xshell的登录

当Xshell客户端通过SSH协议连接服务器时,sshd守护进程接受连接后创建子进程处理认证,认证成功后通过fork()+exec()启动用户Shell(如bash),并将其标准输入/输出/错误绑定到Xshell的伪终端(/dev/pts/X),最终形成sshd子进程→bash进程的父子关系,用户即可通过终端与bash交互

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 21:05:45

昇腾CANN/GE矩阵乘API

aclblasCreateHandleForHgemm 【免费下载链接】ge GE&#xff08;Graph Engine&#xff09;是面向昇腾的图编译器和执行器&#xff0c;提供了计算图优化、多流并行、内存复用和模型下沉等技术手段&#xff0c;加速模型执行效率&#xff0c;减少模型内存占用。 GE 提供对 PyTorc…

作者头像 李华
网站建设 2026/9/10 21:01:35

Python股票量化分析工作流:从数据获取到回测验证

简介&#xff1a;本资源是一套高完成度的毕业设计项目&#xff0c;面向计算机及相关专业本科生、研究生及机器学习初学者&#xff0c;聚焦股票价格预测与量化分析实战场景&#xff0c;提供从数据获取、特征工程、模型训练到结果可视化的完整技术链路。压缩包共2000个文件&#…

作者头像 李华
网站建设 2026/9/10 20:59:45

CANN/ge废弃配置参数说明

后续版本废弃配置 【免费下载链接】ge GE&#xff08;Graph Engine&#xff09;是面向昇腾的图编译器和执行器&#xff0c;提供了计算图优化、多流并行、内存复用和模型下沉等技术手段&#xff0c;加速模型执行效率&#xff0c;减少模型内存占用。 GE 提供对 PyTorch、TensorFl…

作者头像 李华
网站建设 2026/9/10 20:57:47

Firefox 149版本多任务处理与硬件加速全面升级

1. Firefox 149版本核心升级解析Mozilla基金会于本月正式推送了Firefox 149稳定版更新&#xff0c;这次版本迭代聚焦于多任务处理能力的全面提升。作为一名长期跟踪浏览器技术演进的从业者&#xff0c;我在实际测试中发现本次更新包含多项底层架构改进&#xff0c;特别是对硬件…

作者头像 李华
网站建设 2026/9/10 20:54:50

智慧医疗中的中心药房系统架构与实施效果

1. 中心药房的概念与行业背景中心药房&#xff08;或称云药房&#xff09;是近年来医疗信息化领域的重要创新模式&#xff0c;它通过集中化药品仓储管理和智能化配送系统&#xff0c;重构了传统医疗机构药品供应流程。我在参与某三甲医院智慧药房建设项目时&#xff0c;亲眼见证…

作者头像 李华
网站建设 2026/9/10 20:53:42

C++与FPGA协同设计:高性能计算与嵌入式系统实践

1. 项目概述&#xff1a;当C遇见FPGA 在嵌入式系统和高性能计算领域&#xff0c;C与FPGA的协同设计正成为解决复杂计算难题的黄金组合。这种设计模式充分利用了C的软件灵活性和FPGA的硬件并行优势&#xff0c;特别适合需要低延迟、高吞吐量的应用场景。我最近完成的一个视频处理…

作者头像 李华