Linux 进程基础 学习笔记
进程定义:进程是操作系统中的一次执行过程,它是操作系统进行资源分配和调度的基本单位;只要用户执行了一个程序,在内核空间就会创建一个task_struct结构体,这个结构体就代表当前的进程,进程运行产生的所有的信息(如进程状态、PID、内存指针等)都被放到这个结构体中保存着;进程执行完之后,task_struct会被内核回收;如果异常崩溃,内核也会清理资源(避免僵尸进程);结构体放在内核空间。
进程定义:进程是操作系统中的一次执行过程,它是操作系统进行资源分配和调度的基本单位;
进程(静态代码)-> 加载到内存 -> 分配资源 进程是程序的 “动态执行过程”
只要用户执行了一个程序,在内核空间就会创建一个task_struct结构体,这个结构体就代表当前的进程,进程运行产生的所有的信息(如进程状态、PID、内存指针等)都被放到这个结构体中保存着;
进程执行完之后,task_struct会被内核回收;如果异常崩溃,内核也会清理资源(避免僵尸进程);

结构体放在内核空间
进程的核心特征
•动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的;
•并发性:任何进程都可以同其他进程一起并发执行;
•独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;
•异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程各自独立、不可预知的速度向前推进;
程序与进程的区别
| 对比维度 | 程序 (Program) | 进程 (Process) |
|---|---|---|
| 定义 | 是静态的指令集合,存储在磁盘上的可执行文件(如 .exe 等);未执行时不占用系统资源。 |
是程序的动态执行过程,是程序运行时的实例,占用 CPU、内存、I/O 等系统资源,有生命周期。 |
| 存在形式 | 静态存在,以文件形式长期存储。 | 动态存在,随程序启动而创建,随执行结束而销毁。 |
| 资源占用 | 不占用 CPU、内存等运行时资源,仅占用磁盘存储空间。 | 占用 CPU、内存、文件句柄、网络端口等系统资源,有独立的地址空间。 |
| 状态 | 无状态(仅为指令和数据的静态集合)。 | 有状态(如运行态、停止态等),状态会随系统调度变化。 |
| 独立性 | 多个程序之间相互独立,无直接关联(除非通过文件等外部方式交互)。 | 每个进程有独立的地址空间和资源,进程间默认不共享数据(需通过进程间通信机制实现)。 |
| 示例 | 如硬盘上的“浏览器.exe”文件。 | 双击“浏览器.exe”后运行的浏览器窗口。 |
程序与进程的关联
•进程是程序的执行过程,一个程序可以对应多个进程(如同时打开多个浏览器窗口);
•程序是进程的“模板”,进程是程序的“运行态体现”;
•进程的执行过程本质是按程序指令逐步推进,程序的逻辑决定进程的行为;
•同一程序的多个进程共享程序的代码段(只读),到各自拥有数据段(独立);
•关闭进程后,程序文件仍存在于磁盘;删除程序文件后,已运行的进程可继续执行(直到依赖文件时出错);
进程的组成
进程是由三个部分组成的,分别为进程控制块(PCB)、文本段、数据段;
•进程控制块(PCB,Process Control Block):PCB是操作系统用于管理和控制进程的核心数据结构,每个进程在内存中都有唯一的PCB,它记录着进程的所有关键信息(如进程识别信息、进程状态信息、内存管理信息、资源占用信息等),是操作系统感知进程存在的依据;
•文本段:是进程中存储可执行指令的内存区域,即程序编译后生成的机器码;为了防止程序意外修改自身指令,文本段通常被设置为只读;如果多个进程运行同一个程序,他们可以共享同一份文本段,节省内存空间;编译后的指令数量是固定的,文本段的大小在进程运行期间不会改变;
•数据段:是用于存储进程运行过程中需要的数据;根据数据“初始化状态”和“可修改性”,分为初始化数据段、未初始化数据段、堆、栈;
虚拟地址与物理地址的映射关系

Linux系统进程类型
Linux系统下有三种进程类型,分别是交互进程、批处理进程和守护进程;
•交互进程:
•定义:由shell维护,需要用户在终端手动启动的进程,通过shell和用户进行交互(用户交互输入/输出);
•特点:依赖终端环境,通常在前台运行,生命周期与用户操作相关;
•批处理进程:
•定义:无需用户实时交互,优先级比较低,按预设任务序列自动运行的进程,通常在后台执行;
•特点:优先级较低(避免占用关键资源),多通过脚本或任务调度工具启动;
•守护进程:
•定义:系统启动时自动运行的后台进程,独立于终端,通常随系统启动而启动,随系统关闭而终止,用于提供持续服务;
•特点:运行时脱离终端;
进程的状态
在Linux系统中,进程会因资源占用、执行阶段不同,呈现多种状态;
•运行状态(R):也称之为可运行状态,就是处于运行状态的进程,正在CPU执行或等待CPU调度;
•可中断睡眠状态(S):进程在等待某个事件(如等待I/O操作、等待特定信号等)完成,可被信号唤醒;
•不可以中断睡眠状态(D):进程正在等待关键硬件操作完成,不能被信号中断,确保数据完整性;
•停止状态(T):进程被暂停执行,通常是收到了特定的信号(如SIGSTOP(暂停进程))或者在调试程序时被调试器暂停,可被信号恢复执行(如SIGCONT);
•僵尸状态(Z):进程已终止,但资源未被回收,等待父进程进行回收;
•死亡态(X):进程彻底终止,资源全部释放,是一个瞬间状态,几乎无法观测到;
进程的附加状态
在Linux系统中,进程除了基础状态之后,还会有一些附加状态标记,用于补充说明进程的特殊属性;
•+(前台进程组):表示进程属于前台进程组,与当前终端直接关联,用户可以通过终端输入直接控制;
•l (多线程进程):表示进程包含线程(LWP),通常对应多线程程序;
•N(低优先级进程):表示进程的nice值为正数(NI > 0),优先级较低,CPU资源优先给其他进程;
•<(高优先级进程):表示进程的nice值为负数(NI < 0),优先级较高,会优先获取CPU资源;
•s(会话leader进程):表示进程是会话首进程,负责管理一个会话中的其他进程;
•L(进程持有锁):表示进程正在持有某个文件锁或者是资源锁,可能在等待其他进程释放锁资源;
进程状态图

进程PID
PID(processid):是进程的唯一身份标识,操作系统给每个进程分配一个数字编号(比如微信的PID可能是1234,浏览器的可能是6789);
PID在Linux中的规则:
•取值:PID是≥0的整数(实际从1开始分配,0号是特殊进程);
•数量限制:系统能创建的进程总数有限,可通过sysctl kernel.pid_max查看上限;
•查看机制:Linux通过 /proc 文件系统暴露进程信息:
•每个运行的进程对应 /proc/[PID]目录(如 PID=80320对应 /proc/80320);
•目录内的status文件存储进程详情(PID、名称、运行状态等);
| 特殊 PID | 进程名称 | 作用与职责 |
|---|---|---|
| 0 号 | idle | 系统启动后的第一个进程,负责空闲 CPU 调度(无其他进程运行时,idle 进程占用 CPU)。 |
| 1 号 | init | 由 0 号进程创建,负责初始化系统硬件、启动服务、回收孤儿进程(如关机时清理残留进程)。 |
| 2 号 | kthreadd | 负责内核进程调度(管理系统后台的内核级任务,如磁盘 I/O、内存回收)。 |
进程的相关命令
ps命令
功能:用于查看当前系统中进程的快照信息,包括进程的PID(进程标识符)、所属用户、占用CPU和内存资源情况等;
| 常用具体命令 | 选项 | 功能 |
|---|---|---|
ps -ef |
-e:列出系统中所有进程-f:以全格式显示进程信息 |
查看当前所有进程 |
ps -aux |
-a:显示所有终端进程-u:以用户资源视角为中心的格式-x:显示无终端进程(如后台服务) |
展示进程资源占用百分比(如占用CPU百分比、占用内存百分比等) |
ps -eo 字段1,字段2... |
-e:列出系统中所有进程-o:自定义输出格式 |
精准提取进程字段(如pid, comm) |
ps -l |
-l:长格式 |
以长格式查看当前终端进程详细信息 |
top命令
功能:动态的显示系统中各个进程的资源使用情况,可以实时查看进程的CPU使用率、内存使用量、线程数等,并且能按照不同的指标进行排序;

htop命令
功能:是一个交互式的进程查看工具,相比top具有更友好的用户界面,支持鼠标操作;可以更加直观地展示进程树结构;

kill命令
功能:用于向进程发送信号,最常见的就是用来终止进程。通过指定进程的PID,发送特定的信号让进程执行相应的操作,比如终止、暂停等等;
| 命令格式 | 信号编号 | 对应信号名称 | 功能说明 |
|---|---|---|---|
kill -l |
- | - | 列出系统中所有可用的信号及其编号 |
kill -2 <pid> |
2 | SIGINT | 向指定进程发送中断信号(相当于 Ctrl+C) |
kill -9 <pid> |
9 | SIGKILL | 强制终止指定进程(无法被捕获或忽略) |
kill -19 <pid> |
19 | SIGSTOP | 暂停指定进程的运行(相当于 Ctrl+Z,无法被捕获) |
kill -18 <pid> |
18 | SIGCONT | 使已暂停的进程恢复运行 |
killall命令
功能:根据进程名来终止进程,当系统中有多个同名进程需要同时终止时,killall就非常方便;
| 命令格式 | 信号编号 | 对应信号名称 | 功能说明 |
|---|---|---|---|
killall 进程名 |
- | - | 终止所有名为“进程名”的进程(默认发送 SIGTERM) |
killall -9 进程名 |
9 | SIGKILL | 强制终止所有同名进程 |
killall -i 进程名 |
- | - | 终止前逐一询问确认(交互模式) |
pstree命令
功能:以树结构显示进程之间的父子关系,从系统初始化init开始,直观地展示整个系统进程的层次结构;

bg/fg命令
| 命令格式 | 功能说明 | 注意事项 |
|---|---|---|
bg [作业号] |
将挂起的进程放到后台继续运行 | 若不指定作业号,默认操作最近一个被挂起的作业;作业号可通过 jobs -l 命令查看获取。 |
fg [作业号] |
把后台运行的进程放到前台终端运行,恢复与终端交互 | 若不指定作业号,默认将最近一个后台作业调至前台;调至前台后,进程会占据终端输入输出,直到进程结束或再次被暂停。 |
nice/renice命令
| 命令 | 功能 | 命令格式 |
|---|---|---|
| nice | 启动进程时设置优先级;未指定值时默认优先级为10 | nice [-n 优先级值] 要执行的命令 |
| renice | 调整已运行进程的优先级;可针对单个进程或某用户的所有进程进行调整 | 针对单进程:renice 新优先级值 -p 进程PID针对用户所有进程: renice 新优先级值 -u 用户名 |
进程的创建
fork函数
| 项目 | 说明 |
|---|---|
| 所需头文件 | #include <sys/types.h>#include <unistd.h> |
| 原型 | pid_t fork(void); |
| 功能 | 复制当前进程,创建子进程 |
| 参数 | 无 |
| 返回值 | 成功:父进程返回子进程的 PID(大于0的整数) |
| 成功:子进程返回 0 | |
| 失败:子进程未被创建,父进程返回 -1,并设置错误码 |
父子进程内存空间
•父进程在fork产生子进程时,用到了写时拷贝的原则;
•如果父子进程中对内存进行读操作,那么内存不会被重新映射物理内存;
•如果父子进程中的任意一方对内存有写操作时,才会重新映射到新的物理内存;

多进程相关函数
进程号获取函数
getpid函数
| 项目 | 内容 |
|---|---|
| 所需头文件 | #include <sys/types.h>#include <unistd.h> |
| 原型 | pid_t getpid(void); |
| 功能 | 获取当前进程自身的进程号 |
| 参数 | 无 |
| 返回值 | 返回当前进程自身的进程号 |
getppid函数
| 项目 | 内容 |
|---|---|
| 所需头文件 | #include <sys/types.h>#include <unistd.h> |
| 原型 | pid_t getppid(void); |
| 功能 | 获取当前进程的父进程的进程号 |
| 参数 | 无 |
| 返回值 | 返回当前进程的父进程的进程号 |
进程退出函数
exit函数
| 项目 | 内容 | |
|---|---|---|
| 所需头文件 | #include <stdlib.h> |
|
| 原型 | void exit(int status); |
|
| 功能 | 正常终止进程,并将 (status & 0377)(按位与运算后的值)返回给父进程。C 标准规定了两个常量:EXIT_SUCCESS 和 EXIT_FAILURE,可传递给 exit()。 |
|
| 参数 | status |
退出状态值。 |
| 返回值 | 无(函数不会返回)。 | |
_exit函数
| 属性 | 内容 | |
|---|---|---|
| 所需头文件 | #include <unistd.h> |
|
| 原型 | void _exit(int status); |
|
| 功能 | 立即终止进程,且 status & 0377(按位与运算后的值)会被返回给父进程。 |
|
| 备注 | C 标准库为 exit 函数规定了 EXIT_SUCCESS 和 EXIT_FAILURE 常量(通常值分别为 0 和 1),也可传递给 _exit 兼容使用。但 _exit 本身是系统调用,不依赖这些宏。 |
|
| 参数 | status |
退出状态值。 |
| 返回值 | 无 | |
资源回收函数
wait函数
| 类别 | 内容 | |
|---|---|---|
| 所需头文件 | #include <sys/types.h>#include <sys/wait.h> |
|
| 原型 | pid_t wait(int *wstatus); |
|
| 功能 | 父进程阻塞,等待任意一个子进程结束;若没有子进程结束,wait会一直等待;当有子进程终止时,它会回收该子进程的资源,并通过wstatus获取子进程的退出状态值。 |
|
| 参数 | wstatus |
用于存储子进程的退出状态值的内存空间首地址。 - 若为 NULL,表示忽略子进程退出时的状态。- 若不为空,表示将子进程退出状态写入该指针指向的内存,供父进程后续用宏解析。 |
| 返回值 | - 成功:返回终止子进程的PID。 - 失败:返回 -1,并设置errno以指示错误原因(例如调用进程没有子进程)。 |
|
wait函数状态解析宏
子进程正常退出:
•WIFEXITED(wstatus):若子进程是正常终止(调用 exit()/_exit() 或从 main() 返回),则返回 true;
•WEXITSTATUS(wstatus):仅当WIFEXITED为 true 时使用,返回子进程的退出状态码(即exit(n)中的n,取低 8 位);
子进程被信号终止:
•WIFSIGNALED(wstatus):若子进程是被信号终止(如SIGKILL等),则返回 true;
•WTERMSIG(wstatus):仅当WIFSIGNALED为 true 时使用,返回导致子进程终止的信号编号(如9对应SIGKILL);
•WCOREDUMP(wstatus):仅当WIFSIGNALED为 true 时使用,若子进程终止时产生了核心转储文件,则返回 true;
子进程被信号暂停:
•WIFSTOPPED(wstatus):若子进程是被信号暂停(仅在使用 WUNTRACED 标志或子进程被跟踪时有效),则返回 true;
•WSTOPSIG(wstatus):仅当 WIFSTOPPED 为 true 时使用,返回导致子进程暂停的信号编号(如 19 对应 SIGSTOP);
子进程被恢复运行:
•WIFCONTINUED(wstatus):若子进程是通过SIGCONT 信号恢复运行,则返回 true;
waitpid函数
| 项目 | 内容 | |
|---|---|---|
| 所需头文件 | #include <sys/types.h>#include <sys/wait.h> |
|
| 原型 | pid_t waitpid(pid_t pid, int *wstatus, int options); |
|
| 功能 | 父进程等待子进程状态变化并获取其状态信息。允许父进程精准控制子进程的范围,可通过 options 调整等待行为(如阻塞/非阻塞)。 |
|
| 参数 | pid |
指定要等待的子进程 • <-1:等待任何进程组ID与进程pid的绝对值相等的子进程• -1:等待任何子进程• 0:等待任何进程组ID与调用进程相同的子进程• >0:等待指定pid的子进程 |
wstatus |
用于存储子进程的退出状态值的内存空间首地址 • 若为 NULL,表示忽略子进程退出时的状态• 若不为空,表示将子进程退出状态写入该指针指向的内存,供父进程后续用宏解析 |
|
options |
标志位(默认模式是阻塞等待模式 options = 0) |
|
| 返回值 | • 成功:返回终止子进程的PID • 若设置非阻塞且没有子进程退出:返回 0• 出错(调用进程没有子进程或调用出错):返回 -1,并设置 errno 指示错误原因 |
|
options参数
| 选项常量 | 作用 | 具体行为 | 典型应用场景 |
|---|---|---|---|
0 |
实现阻塞等待 | 父进程暂停执行,直到指定的子进程状态发生变化(如退出、被暂停或恢复) | 常规子进程同步等待,例如批处理任务中等待子进程完成 |
WNOHANG |
实现非阻塞等待 | 调用 waitpid 时,若指定子进程未退出,函数立即返回 0,父进程无需阻塞,可继续执行其他任务 |
父进程需要轮询监控子进程状态,例如守护进程或后台任务管理器 |
WUNTRACED |
捕获子进程暂停状态 | 当子进程因信号(如 SIGSTOP)停止运行时,waitpid 也能返回该子进程的 PID,父进程可以感知暂停事件 |
调试器或需要处理子进程暂停逻辑的程序,例如 shell 作业控制 |
WCONTINUED |
捕获子进程恢复运行状态 | 当已停止的子进程通过 SIGCONT 信号恢复运行时,waitpid 返回该子进程的 PID,父进程可以感知恢复事件 |
需要跟踪子进程完整生命周期(暂停-恢复)的场景,如进程监控工具或作业控制系统 |
waitpid函数状态解析宏
子进程正常退出:
•WIFEXITED(wstatus):若子进程是正常终止(调用 exit()/_exit() 或从 main() 返回),则返回 true;
•WEXITSTATUS(wstatus):仅当WIFEXITED为 true 时使用,返回子进程的退出状态码(即exit(n)中的n,取低 8 位);
子进程被信号终止:
•WIFSIGNALED(wstatus):若子进程是被信号终止(如SIGKILL等),则返回 true;
•WTERMSIG(wstatus):仅当WIFSIGNALED为 true 时使用,返回导致子进程终止的信号编号(如9对应SIGKILL);
•WCOREDUMP(wstatus):仅当WIFSIGNALED为 true 时使用,若子进程终止时产生了核心转储文件,则返回 true;
子进程被信号暂停:
•WIFSTOPPED(wstatus):若子进程是被信号暂停(仅在使用 WUNTRACED 标志或子进程被跟踪时有效),则返回 true;
•WSTOPSIG(wstatus):仅当 WIFSTOPPED 为 true 时使用,返回导致子进程暂停的信号编号(如 19 对应 SIGSTOP);
子进程被恢复运行:
•WIFCONTINUED(wstatus):若子进程是通过SIGCONT 信号恢复运行,则返回 true;
文件描述符重定向函数
dup函数
| 项目 | 内容 | |
|---|---|---|
| 所需头文件 | #include <unistd.h> |
|
| 原型 | int dup(int oldfd); |
|
| 功能 | 复制一个已有的文件描述符。新文件描述符采用最小未分配的原则分配。 | |
| 参数 | oldfd |
旧的文件描述符 |
| 返回值 | 成功:返回新的文件描述符 失败:返回 -1,并设置错误码 |
|
dup2函数
| 项目 | 内容 | |
|---|---|---|
| 所需头文件 | #include <unistd.h> |
|
| 原型 | int dup2(int oldfd, int newfd); |
|
| 功能 | 复制一个已有的文件描述符 oldfd新文件描述符使用 newfd 中指定的文件描述符编号若 newfd 此前已打开,会在重用该描述符前自动静默关闭它 |
|
| 参数 | oldfd |
旧的文件描述符 |
newfd |
新的文件描述符 | |
| 返回值 | 成功:返回新的文件描述符 失败:返回 -1,并设置错误码 |
|
进程程序替换函数
exec函数族
| 所需头文件 | #include <unistd.h> |
|---|---|
| 函数原型 | int execlp(const char *file, const char *arg, ... /* (char *) NULL */); |
int execvp(const char *file, char *const argv[]); |
|
int execl(const char *path, const char *arg, ... /* (char *) NULL */); |
|
int execv(const char *path, char *const argv[]); |
|
int execle(const char *path, const char *arg, ... /*, (char *) NULL, char * const envp[] */); |
|
int execvpe(const char *file, char *const argv[], char *const envp[]); |
|
| 函数返回值 | 成功:无返回(进程已被新程序替换) 失败:返回 -1,并设置 errno 来指示错误 |
execlp函数
| 项目 | 内容 | |
|---|---|---|
| 所需头文件 | #include <unistd.h> |
|
| 原型 | int execlp(const char *file, const char *arg, ... /* (char *) NULL */); |
|
| 功能 | 在环境变量 PATH 所指定的目录中查找由 file 参数指定的程序文件,并使用该程序替换当前进程的映像(即当前进程的代码、数据、堆栈等被新程序完全替换,执行流从新程序的入口开始)。 |
|
| 参数 | file |
要执行的程序文件名(无需提供完整路径,系统会在 PATH 环境变量指定的目录中查找该程序) |
arg |
传递给新程序的参数列表,需要逐个列出参数,并且以 NULL 作为结束标志 |
|
| 返回值 | - 成功:无返回(因为当前进程已被新程序替换,原进程不再存在)。 - 失败:返回 -1,并设置 errno 以指示错误类型。 |
|
execvp函数
| 项目 | 说明 | |
|---|---|---|
| 所需头文件 | #include <unistd.h> |
|
| 原型 | int execvp(const char *file, char *const argv[]); |
|
| 功能 | 在环境变量 PATH 所指定的目录中查找由 file 参数指定的程序文件,并使用该程序替换当前进程的映像。 |
|
| 参数 | file |
要执行的程序文件名(无需提供完整路径,系统会在环境变量指定的目录中查找该程序) |
argv |
指向字符指针数组的指针(数组最后一个元素必须是 NULL) |
|
| 返回值 |
- 成功:无返回(进程已被新程序替换)。 |
|
特殊进程
孤儿进程
定义:当一个进程的父进程先于它终止,该进程就会成为孤儿进程;
产生原因:父进程意外崩溃、被强制终止(如kill -9),或父进程主动退出但未正确处理子进程;
特点:
•失去父进程后,会被系统的“祖先进程”(linux中是init或system,PID=1)收养;
•仍能正常运行,完成自身任务后会正常终止,不会占用额外资源;
影响:
•本身是系统正常处理机制的结果,无负面影响,反而避免了进程成为“无主进程”;
•例如:若父进程因bug崩溃,子进程被init收养后可继续提供服务;
僵尸进程
定义:进程终止后,内核未释放其进程控制块(PCB),该进程状态变为Z(僵尸态),成为僵尸进程;
产生原因:父进程未调用wait()或waitpid()等系统调用,读取子进程的退出状态(如退出码、终止原因),导致内核无法回收PCB;
特点:
•已终止运行,不再执行任何代码,但PCB仍占用内存资源(如PID、退出状态);
•通过ps命令中显示状态为Z或者是Z+(僵尸态),名称可能为<defunct>;
影响:
•系统PID数量有限,大量僵尸进程会耗尽PID资源,导致新进程进行无法创建;
•不占用用户空间的内存数据段,但内核空间的PCB资源仍被占用且无法使用;
处理方式:
•预防:父进程调用wait()/waitpid()主动回收子进程状态;
•清除:kill-9无法直接杀死僵尸进程(其已终止,无运行实体);
父进程未处理,可终止父进程(僵尸进程被1号进程收养,1号进程会定期回收其PCB);
守护进程
定义:运行在后台的特殊进程,独立于控制终端,用于持续提供系统服务;
设计目的:不受用户登录/注销影响,长期稳定运行(如网络服务、定时任务);
特点:
•脱离终端:无控制终端,避免终端关闭导致进程终止;
•后台运行:通过ps命令查看状态通常为S(休眠),名称多以d结尾(如httpd、systemd);
•父进程为1号进程:启动后会与原本父进程脱离,被1号进程收养;
•环境干净:默认不继承终端信号,工作目录通常为\,文件描述符(如stdin/stdout/stderr)被关闭或重定向到/dev/null;
守护进程创建流程
•父进程fork( )后退出,子进程成为孤儿进程(被1号收养);
•子进程调用setsid( )函数创建新会话,脱离原终端控制;
•调用chdir( )函数改变进程的工作目录到一个不会被删除和卸载的目录下;
•使用umask( )函数修改创建文件的掩码;
•关闭所有从父进程继承过来的文件描述符集合;
•使用dup( )或者是dup2( )将标准输入/标准输出/标准出错都重定向到文件中;
•开启自己的服务;

代码示例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main() {
pid_t pid = fork();
if (pid < 0) exit(1);
if (pid > 0) exit(0); // 父进程退出
// 子进程成为孤儿,调用 setsid 成为新会话首领
if (setsid() < 0) exit(1);
// 再次 fork,防止意外获得终端
pid = fork();
if (pid < 0) exit(1);
if (pid > 0) exit(0);
// 改变工作目录
chdir("/");
// 重设文件权限掩码
umask(0);
// 关闭所有文件描述符(这里简单关闭标准三剑客)
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// 重定向到 /dev/null
open("/dev/null", O_RDWR); // 0
dup(0); // 1
dup(0); // 2
// 守护进程的主逻辑
while (1) {
// 做一些后台工作,比如每秒记录一次时间
syslog(LOG_INFO, "Daemon is running...");
sleep(10);
}
return 0;
}
setsid函数
| 项目 | 内容 |
|---|---|
| 所需头文件 | #include <sys/types.h>#include <unistd.h> |
| 原型 | pid_t setsid(void); |
| 功能 | 创建一个新会话,并让调用该函数的进程成为这个新会话的首进程,同时也成为新进程组的组长 |
| 参数 | 无 |
| 返回值 | 成功:返回调用进程的新会话标识符 失败:-1,重置错误码 |
chdir函数
| 项目 | 内容 | |
|---|---|---|
| 所需头文件 | #include <unistd.h> |
|
| 原型 | int chdir(const char *path); |
|
| 功能 | 将调用进程的当前路径修改为参数所指定的目录 | |
| 参数 | path |
新的工作目录 |
| 返回值 | 成功:0失败: -1,并设置错误码 |
|
umask函数
| 项目 | 内容 | |
|---|---|---|
| 所需头文件 | #include <sys/types.h>#include <sys/stat.h> |
|
| 原型 | mode_t umask(mode_t mask); |
|
| 功能 | 修改进程的文件创建掩码(权限掩码) | |
| 参数 | mask |
新的掩码值 实际文件权限 = |
| 返回值 | 总是成功,返回之前的掩码值 | |
三者的核心区别
| 对比维度 | 孤儿进程(Orphan Process) | 僵尸进程(Zombie Process) | 守护进程(Daemon Process) |
|---|---|---|---|
| 定义 | 父进程先于子进程退出,被子进程被1号进程(init/systemd)收养的进程 | 子进程先退出,但父进程未调用 wait/waitpid 回收其PCB,导致进程状态为 Z 的进程 |
脱离控制终端、在后台长期运行的系统服务进程(如 sshd、nginx) |
| 产生原因 | 父进程意外退出或主动退出,未等待子进程 | 子进程退出后,父进程未调用 wait/waitpid 回收其退出状态 |
程序主动调用 setsid 等函数创建,脱离终端并后台运行 |
| 进程状态 | 正常运行状态,PPID=1(被 init 收养) | 僵尸状态,标记为 <defunct> |
后台运行状态,无控制终端,名称常以 d 结尾(如 httpd) |
| 资源占用 | 占用正常进程资源(代码/数据/PCB) | 仅占用 PCB 资源(PID、退出状态),不占用代码段/数据段 | 占用正常进程资源,长期稳定运行 |
| 危害 | 无直接危害,被1号进程正常管理 | 大量积累会耗尽 PID 资源,导致新进程无法创建 | 无危害,是系统正常运行的必要服务(如网络服务、定时任务) |
| 处理方式 | 无需手动处理,1号进程会自动回收其资源 | 父进程调用 wait/waitpid 主动回收;或终止父进程,由1号进程回收 |
无需处理,随系统启动而启动、终止而终止,可通过 systemctl 等工具管理 |
| 典型场景 | 父进程未等待子进程就退出(如脚本中后台运行的子进程) | 父进程长期运行且未处理子进程退出(如服务器程序漏洞) | 系统服务(如 sshd、crond、nginx) |
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)