文章目录
- 1. 引言
- 2. 进程&线程——概念
- 3. 进程控制块/进程描述符(PCB)
- 4. 进程内核栈(Kernel Stack)
- 5. 进程 ID(PID)
- 6. 进程状态
- 7. 进程创建
-
- 7.1. 进程之间的关系
- 7.2. 进程创建的写时拷贝机制(copy-on-write)
- 7.3. fork() 函数的入口
- 7.4. 创建新进程的核心函数 kernel_clone()
- 7.5. kernel_clone() 的核心函数 copy_process()
- 7.6. 实现 fork() 写时拷贝的关键所在 copy_process() 中的 copy_mm()
- 7.7. copy_process() 的核心函数 dup_task_struct()
- 7.8. 分配进程描述符 alloc_task_struct_node()
- 7.9. 分配进程内核栈 alloc_thread_stack_node()
- 7.10. fork() 函数的简要总体框图
- 8. exit() 进程退出
-
- 8.1. exit() 系统调用的定义
- 8.2. do_exit() 函数
-
- 8.2.0. do_exit() 的参数和返回值
- 8.2.1. 检查和同步线程组退出
- 8.2.2. 清理与调试相关的资源
- 8.2.3. 取消 I/O 和信号处理
- 8.2.4. 检查线程组是否已终止
- 8.2.5. 释放系统资源
- 8.2.6. 释放线程和调度相关资源
- 8.2.7. 通知父进程
- 8.2.8. 减少进程栈引用计数,设置进程状态 DEAD 并切换进程
- 8.2.9. 进程消亡
- 8.2.10. put_task_stack() 释放内核栈
- 8.2.11. release_task_stack()
- 8.2.12. free_thread_stack()
- 8.2.13. thread_stack_delayed_free()
- 8.2.14. thread_stack_free_rcu()
- 8.2.15. try_release_thread_stack_to_cache()
- 8.3. do_exit() 函数小结
- 9. 阻塞等待退出
- 10. 进程退出为什么延时销毁?
- 11. 遗留问题
- 12. 处理遗留问题
- 13. 线程
- 14. 创建线程
- 15. 第三章总结
- #附
- #01. 计算 task_struct 大小
- #02. 验证内核栈大小
- #03. 验证内核栈结构
- #04. 验证栈指针位置
- #05. init 进程
1. 引言
进程是 Linux
操作系统抽象概念中最基本的一种。本文将和读者一起学习有关 Linux
内核中对进程、线程的概念;然后再一起研究在 Linux
内核中是如何管理每个进程,本文只涉及对进程以及线程生命周期的介绍(进程是如何创建、消亡)。我们的操作系统存在的目的就是为了更好的运行用户程序,由此可见进程管理在操作系统中的地位可谓是至关重要的。而有关进程调度内容笔者将放在下一篇文章中详述,虽然这些都属于进程管理的范畴,不过由于笔者是按照《Linux 内核设计与实现》第三版并结合 Linux 6.15.0-rc2
内核代码来展开讨论,因此这里的探讨顺序将会与书籍原文保持一致。
2. 进程&线程——概念
在计算机科学领域,有关进程(Process
)较为官方的定义是,进程是“正在执行的程序实例”。与静态存储在磁盘上的程序文件不同,进程具有动态的执行上下文,包括程序计数器(PC
)、寄存器集、堆栈以及进程控制块(PCB
)中记录的资源分配信息。与之对应衍生出的概念线程(Thread
),较为官方的定义是,线程是“正在执行的程序指令序列中的最小可独立调度单元”。它包含程序计数器、寄存器状态、堆栈以及线程控制块(TCB
)等上下文信息。线程也被称为轻量级进程,因为它与同属一个进程的其他线程共享同一地址空间和打