1. 多任务与并发概述
在单核或多核处理器上,让操作系统具备同时处理多个任务 的能力称为多任务(Multitasking)。
●并发(Concurrency) :微观上单核 CPU 采用时间片轮询算法在多个任务之间快速切换,宏观上表现为多个任务"同时"执行。
●并行(Parallelism):在多核 CPU 或多处理器系统中,不同的任务同时在不同的物理核心上真实地独立运行。
实现多任务的常见方式包括:多进程 与 多线程。
2. 深入理解 Linux 进程
2.1 进程与程序的区别
|--------------|---------------------|---------------------|
| 对比维度 | 程序(Program) | 进程(Process) |
| 概念定义 | 静态的数据指令集合 | 正在执行的程序 |
| 存储位置 | 外存/硬盘(如 a.out) | 内存 + CPU 寄存器 |
| 生命周期 | 永久存在 | 动态的,从启动到消亡 |
| 资源消耗 | 仅占用磁盘空间 | 消耗内存空间与 CPU 计算资源 |
核心结论 :进程是操作系统资源分配的最小单位。
2.2 进程的 0-4G 内存布局
当一个进程被创建时,操作系统会为其分配一个 4G(32 位系统) 的虚拟地址空间,分为:
●0 - 3G:用户空间(各个进程相互独立)
●3G - 4G:内核空间(所有进程共享)

3. 进程的调度与状态转换
3.1 CPU 调度算法
操作系统内核通过调度器(Scheduler)分配 CPU 资源,常见的调度策略包括:
1.时间片轮询算法(Round-Robin)
2.先来先服务(FCFS) / 短作业优先(SJF)
3.高优先级优先算法(Priority Scheduling)
3.2 Linux 进程状态(七态模型)
在 Linux 中,进程在生命周期内会经历如下状态变迁:

|--------------|-------------------------------|--------------------------------|
| 状态代码 | 状态名称 | 详细说明 |
| R | Running / Runnable | 运行态/就绪态:正在 CPU 上运行或等待 CPU 调度 |
| S | Interruptible Sleep | 可中断睡眠态:阻塞等待资源(如等待键盘输入),可被信号唤醒 |
| D | Uninterruptible Sleep | 不可中断睡眠态:进程不响应信号打断(通常发生在驱动 I/O) |
| T | Stopped | 暂停态:收到 SIGSTOP 信号后暂停执行 |
| Z | Zombie | 僵尸态:进程已终止,但其资源尚未被父进程回收 |
| X | Dead | 消亡态:进程资源被彻底释放回收 |
4. 进程管理常用命令
在 Linux 终端中,可以使用以下命令查看与控制进程:
1.ps -aux :查看系统中所有进程的详细参数(PID、CPU/内存占用率、进程状态等)。
ps -aux | grep a.out
2.ps -ef:查看进程的树形父子关系(PID 与 PPID)。
3.top:动态实时查看进程状态与系统 CPU、内存占用率。
4.pstree -sp <PID>:查看指定 PID 进程的族谱/创建关系。
5.kill:给指定进程发送控制信号。
-
- kill -l:查看系统支持的所有信号。
- kill -9 <PID>:强制结束指定 PID 的进程。
6.jobs / fg:查看后台进程与将后台进程切换至前台。
5. 进程控制 API 实战
5.1 创建子进程 fork()
操作系统通过 fork() 创建新进程。fork() 调用完成后,系统会将父进程 0-3G 的用户空间完整拷贝一份给子进程(写时复制 Copy-On-Write 机制)。
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
●返回值:
○在父进程中 :返回创建成功的 子进程 PID(pid > 0)。
○在子进程中 :固定返回 0(pid == 0)。
○失败:返回 -1。
注意:
1.父子进程共享 3G-4G 内核空间 ,但各自 0-3G 用户空间相互独立,不能直接通过共享全局变量进行通信。
2.获取进程 PID API:getpid() 获取当前进程 PID,getppid() 获取父进程 PID。
C语言代码实战:fork() 使用示例
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void) {
int num = 100;
printf("Before fork, PID = %d\n", getpid());
pid_t pid = fork();
if (pid < 0) {
perror("fork error");
return -1;
}
else if (pid == 0) {
// 子进程逻辑
num += 50;
printf("Child PID: %d, PPID: %d, num = %d\n", getpid(), getppid(), num);
}
else {
// 父进程逻辑
sleep(1); // 让子进程先运行
printf("Parent PID: %d, Child PID: %d, num = %d\n", getpid(), pid, num);
}
return 0;
}
5.2 进程的退出 exit()
进程退出的常见方式:
- main 函数中使用 return 退出。
- 调用标准 C 库函数 exit() 或系统调用 _exit() / _Exit()。
- 外部发送信号强行终止(如 kill -9 PID)。
#include <stdlib.h>
void exit(int status);
●参数 status:0 表示正常退出;非 0 表示因异常或特定错误退出。
5.3 孤儿进程与僵尸进程处理
(1) 孤儿进程(Orphan Process)
●定义 :父进程先退出,子进程仍在运行。子进程成为孤儿进程。
●处理机制 :孤儿进程会被系统顶级进程(init 或 systemd,PID=1)收养,子进程结束后由系统回收,不会造成系统资源泄露。
(2) 僵尸进程(Zombie Process)
●定义:子进程已经退出,但父进程没有调用 wait() / waitpid() 回收其内核空间资源(PCB)。
●危害:过多僵尸进程会导致 PID 号被耗尽,系统无法创建新进程。
(3) 解决僵尸进程:wait() 与 waitpid()
父进程可以调用 wait() 或 waitpid() 阻塞/非阻塞等待子进程结束并回收其资源:
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
C语言代码实战:wait() 回收子进程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void) {
pid_t pid = fork();
if (pid < 0) {
perror("fork error");
return -1;
}
else if (pid == 0) {
// 子进程逻辑
printf("Child process running... PID: %d\n", getpid());
sleep(2);
exit(10); // 子进程带状态码 10 退出
}
else {
// 父进程逻辑
int status = 0;
printf("Parent process waiting for child...\n");
pid_t z_pid = wait(&status); // 阻塞等待并回收子进程
if (WIFEXITED(status)) {
printf("Child (PID: %d) exited with code: %d\n",
z_pid, WEXITSTATUS(status));
}
}
return 0;
}
6. 总结
1.进程 是 Linux 系统分配资源的基本单位,拥有独立 0-3G 用户空间,安全稳定。
2.使用 fork() 可以轻松创建多进程,父子进程通过返回值区分逻辑。
3.必须注意避免产生 僵尸进程 ,通过 wait() / waitpid() 显式回收子进程资源。
4.由于进程间用户内存空间隔离,实现多进程协同需进一步学习 IPC(进程间通信:管道、信号、共享内存、消息队列、信号量)。