从零到壹嵌入式Linux编程实战教程课:第9课 进程管理子系统(一):进程概念与创建 模块二:内核核心机制
2026/4/24 20:33:21 网站建设 项目流程

文章目录

    • 一、课程目标
    • 二、进程基本概念
      • 程序 vs 进程
      • 线程 vs 进程
    • 三、内核核心:进程描述符 task_struct
    • 四、进程状态
    • 五、进程创建原理
      • 写时复制 COW(Copy-On-Write)
    • 六、进程创建完整流程
    • 七、示例代码1:fork 创建子进程(用户态)
    • 八、示例代码2:内核态查看进程信息
    • 九、课堂练习
    • 十、课后作业
    • 十一、本章总结
    • 十二、核心关键词
  • 第9课 课程回顾总结
  • 上节课答案 第8课 用户态与内核态的区别及切换 实战作业代码
    • 代码功能说明
    • 注意事项

一、课程目标

  1. 理解进程本质、组成结构与生命周期

  2. 掌握 task_struct 进程描述符的核心作用

  3. 理解进程与程序、线程、轻量级进程的区别

  4. 掌握 fork / vfork / clone 三种创建方式原理

  5. 理解写时复制(Copy-On-Write)机制

  6. 能分析进程创建完整流程,为进程调度、驱动通信打基础


二、进程基本概念

进程是可执行程序的运行实例,是系统资源分配与调度的基本单位。

一个进程包含:独立地址空间、代码段、数据段、堆栈、文件描述符、页表、PCB。

程序 vs 进程

  • 程序:静态二进制文件,存放在磁盘

  • 进程:动态运行实体,有生命周期、占用内存与CPU

线程 vs 进程

  • 进程:独立资源、独立地址空间

  • 线程:共享进程资源,仅独有栈与寄存器

  • Linux 中线程本质是轻量级进程(LWP)


三、内核核心:进程描述符 task_struct

Linux 内核使用task_struct结构管理所有进程,是 PCB 的具体实现。

包含内容:

  • 进程标识(pid、tgid)

  • 状态信息(运行、就绪、等待、停止、僵尸)

  • 调度信息(优先级、调度类、时间片)

  • 地址空间(mm_struct、页表)

  • 打开文件、信号、资源使用统计

  • 父子进程关系、链表链接

task_struct 会被链接成双向循环链表,方便内核遍历管理所有进程。


四、进程状态

  1. TASK_RUNNING运行/就绪

  2. TASK_INTERRUPTIBLE可中断睡眠

  3. TASK_UNINTERRUPTIBLE不可中断睡眠

  4. TASK_STOPPED暂停(被信号停止)

  5. EXIT_ZOMBIE僵尸状态(子进程退出,父进程未wait)

状态切换:

运行 → 等待事件 → 睡眠

事件到达 → 唤醒 → 就绪

调度运行 → 运行

退出 → 僵尸 → 父进程回收 → 销毁


五、进程创建原理

Linux 进程创建三剑客:

  1. fork():创建子进程,写时复制

  2. vfork():共享父进程地址空间,阻塞父进程

  3. clone():底层系统调用,可创建线程/轻量级进程

内核底层统一调用do_fork() / kernel_clone()

写时复制 COW(Copy-On-Write)

fork 时并不立即复制全部页,而是共享页,标记“只读”。

任一进程试图修改时,才真正复制一页。

优点:高效、节省内存、加速创建。


六、进程创建完整流程

  1. 用户态调用 fork()

  2. 进入内核态,执行 sys_fork

  3. 分配新 pid

  4. 分配 task_struct,复制父进程属性

  5. 初始化进程资源、文件表、信号处理

  6. 建立地址空间,共享页表(COW)

  7. 将子进程加入运行队列,标记为就绪

  8. 返回用户态:父进程返回子pid,子进程返回0


七、示例代码1:fork 创建子进程(用户态)

#include <stdio.h> #include <unistd.h> #include <sys/types.h> int main() { pid_t pid; printf("父进程:pid=%d,准备创建子进程\n", getpid()); pid = fork(); if (pid < 0) { perror("fork失败"); return -1; } if (pid == 0) { printf("子进程:pid=%d,ppid=%d,我运行了\n", getpid(), getppid()); while(1); } else { printf("父进程:pid=%d,创建子进程成功,子pid=%d\n", getpid(), pid); while(1); } return 0; }

八、示例代码2:内核态查看进程信息

#include <linux/module.h> #include <linux/sched.h> #include <linux/init.h> static int __init proc_info_init(void) { printk("当前进程 pid: %d\n", current->pid); printk("进程名称: %s\n", current->comm); printk("进程状态: %ld\n", current->state); printk("父进程 pid: %d\n", current->parent->pid); return 0; } static void __exit proc_info_exit(void) { printk("模块卸载\n"); } module_init(proc_info_init); module_exit(proc_info_exit); MODULE_LICENSE("GPL");

九、课堂练习

  1. 简述进程与程序、线程的区别。

  2. Linux 用哪个数据结构管理进程?包含哪些内容?

  3. 列出Linux 5种进程状态。

  4. 什么是写时复制?优点是什么?

  5. fork 创建子进程后,父子进程的返回值分别是什么?


十、课后作业

  1. 画图表示进程生命周期与状态切换。

  2. 用 fork 编写程序:创建一个子进程,子进程打印10次“child”,父进程打印10次“parent”。

  3. 解释:为什么 fork 后子进程不立即复制全部地址空间?

  4. 简述内核创建进程的完整流程。

  5. 说明 fork、vfork、clone 的适用场景。


十一、本章总结

本章讲解进程管理子系统核心基础:进程定义、task_struct 结构、五种进程状态、生命周期切换,以及 fork / vfork / clone 创建机制。

重点掌握写时复制(COW)是Linux高效创建进程的关键。

进程是调度、内存、中断、文件系统的基础,理解进程创建与管理,是掌握Linux内核的关键一步。


十二、核心关键词

进程、task_struct、进程状态、fork、写时复制、COW、子进程、pid、进程创建、轻量级进程


第9课 课程回顾总结

本课系统讲解了Linux进程管理子系统的核心基础内容,重点介绍进程概念、进程描述符task_struct、五种进程状态及切换流程,以及fork、vfork、clone三种进程创建机制。课程明确了进程与程序、线程的本质区别,强调线程在Linux中以轻量级进程形式实现。内核通过task_struct结构体完整记录进程的PID、状态、调度信息、地址空间、文件描述符等所有运行信息,是进程管理的核心数据结构。课程详细解析了运行、可中断睡眠、不可中断睡眠、暂停、僵尸五种进程状态及其切换条件,帮助理解内核如何管理任务。进程创建以fork为核心,底层依靠kernel_clone完成,写时复制机制大幅提升创建效率并节省内存,是Linux优化的关键技术。本课通过用户态与内核态两段示例代码,直观展示了进程创建方法与内核查看进程信息的方式。通过学习,能够理解进程在内核中的表示、运行流程、创建原理,掌握进程生命周期管理思路。本章知识是后续学习进程调度、内存管理、进程通信、驱动开发的重要基础,对理解Linux系统运行机制、定位进程异常、分析系统性能问题具有重要意义。


上节课答案 第8课 用户态与内核态的区别及切换 实战作业代码

#include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <sys/syscall.h> #include <sys/types.h> int main() { char buf[64] = "test: user to kernel switch\n"; int fd; printf("【用户态】开始执行,调用open系统调用\n"); fd = open("/tmp/test.log", O_RDWR | O_CREAT, 0666); if (fd < 0) { perror("open failed"); return -1; } printf("【用户态】调用write系统调用\n"); write(fd, buf, sizeof(buf)); printf("【用户态】调用getpid系统调用\n"); pid_t pid = syscall(SYS_getpid); printf("【用户态】当前进程PID=%d\n", pid); printf("【用户态】调用close系统调用\n"); close(fd); printf("【用户态】所有系统调用执行完毕\n"); return 0; }

代码功能说明

该程序是第8课用户态与内核态切换实战作业,通过连续调用open、write、getpid、close四个典型系统调用,完整演示用户态主动进入内核态的全过程。程序在用户态准备数据,触发软中断进入内核态,由内核完成文件创建、写入、获取PID、关闭文件等操作,完成后返回用户态继续执行。代码直观展示系统调用是态切换最主要、最安全的方式,帮助理解CPU特权级切换、上下文保存与恢复的底层逻辑,适合用于验证用户态与内核态的切换流程、观察切换触发点,巩固态切换理论知识,为后续系统编程与驱动开发打基础。

注意事项

  1. 编译命令:gcc switch.c -o switch

  2. 运行需有/tmp目录写入权限

  3. 每次系统调用都会触发一次用户态→内核态→用户态切换

  4. 内核执行期间用户程序会暂停,不可同时占用CPU

  5. 系统调用由软中断指令实现,应用层不可直接操作寄存器

  6. 若出现权限错误,可检查文件路径与权限配置

  7. 可使用 strace ./switch 观察所有系统调用过程


需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询