Featured image of post 进程与线程

进程与线程

在现代操作系统中,进程线程虚拟地址是支撑高效执行、内存管理与资源隔离的三大核心概念。它们相互配合,共同保证系统的稳定性、安全性与并发性能。

进程:资源隔离与调度的基本单位

概念

  • 进程:正在运行的程序实例,拥有独立的地址空间、数据段、堆与栈,以及各类系统资源(文件描述符、信号、IPC 对象等)。

创建与执行

  • 创建:Linux 中通过 fork() 复制父进程,再用 exec() 系列函数加载新程序。

    • fork()——复制当前进程

      父进程调用 fork(),内核在后台复制出一个“子进程”,这个子进程和父进程几乎一模一样(地址空间、打开的文件描述符等都拷贝或共享)。

    • execve()(或其它 exec* 系列函数)——在子进程里加载新程序

      子进程中立即调用 execve("/path/to/newprog", argv, envp),内核就会丢弃掉原来的地址空间,把可执行文件 /path/to/newprog 映射进来,初始化全新的代码段、数据段、堆栈,真正运行“一个全新的进程镜像”。

  • 调度:内核调度器(scheduler)负责分配 CPU 时间片,维护多任务并发运行。

进程间通信(IPC)

由于进程地址空间独立,IPC 机制尤为重要:

方式场景优势注意点
管道(Pipe)父子进程简单、快速仅限亲缘进程,单向
命名管道任意本地进程双向、可见文件系统性能略低
消息队列异步通信支持优先级、可靠传输大量小消息时开销增大
共享内存大块数据交换零拷贝、高吞吐需同步机制(锁、信号量)
套接字(Socket)本地/跨网络进程灵活、多协议网络开销相对较大
信号(Signal)异步通知轻量级、实时性好数据传输能力有限

IPC(进程间通信,Inter-Process Communication) 是指在操作系统中,不同进程之间为交换数据或进行同步而提供的一系列机制。

由于操作系统给每个进程分配了独立的地址空间,直接读写对方内存是不被允许的,IPC 就是为了解决“进程如何安全、高效地互相协作”而产生的。

线程:轻量级执行流与并行处理

概念

  • 线程:依附于进程的执行单元,共享进程的地址空间和大部分资源,但拥有各自的寄存器上下文和栈。

创建与管理

  • Linux 实现:基于 clone() 系统调用;POSIX 线程库(pthread)提供了更友好的 API。
  • 切换开销:比进程轻量,适用于高并发场景。

并发挑战

  • 竞态条件:无同步的并发访问可能导致数据不一致。
  • 死锁:多线程间相互等待锁时出现永久阻塞。
  • 活锁与饥饿:线程过度谦让或被长期剥夺执行机会。

示例(Rust 风格伪代码):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
let counter = Arc::new(Mutex::new(0));
let handles: Vec<_> = (0..10).map(|_| {
    let c = Arc::clone(&counter);
    thread::spawn(move || {
        let mut num = c.lock().unwrap();
        *num += 1;
    })
}).collect();
for h in handles { h.join().unwrap(); }
println!("Result: {}", *counter.lock().unwrap());

虚拟地址:抽象内存与安全保护

概念

  • 虚拟地址:操作系统为每个进程提供的连续逻辑地址空间,与物理内存无直接一一映射。

管理机制

  1. 分页(Paging)

    • 页大小:通常 4 KB,也有大页(2 MB/1 GB)。
    • 多级页表:如 x86_64 的 4 级页表,减少内存占用。
  2. 地址转换

    1
    2
    
    虚拟地址 = [页目录索引][页表索引][页内偏移]
    物理地址 = 页框号 + 偏移
    
    • 通过 MMU 与 TLB 快速完成转换。
  3. 保护与优化

    • 访问权限:读/写/执行标志。
    • 用户/内核隔离:防止越权访问。
    • 写时复制(COW):延迟复制,降低 fork 开销。

能当做 IPC 吗?

  • 虚拟地址本身不共享,不能直接跨进程使用。
  • 共享内存mmap(MAP_SHARED) 是利用虚拟地址“映射”同一段物理页到不同进程,从而实现高效的 IPC。
  • 你只需要在各自进程里拿到映射后自己的虚拟指针,就能像访问本地内存一样进行读写。

协程:更轻量的用户态并发

概念

  • 协程(Coroutine):用户态的轻量级执行单元,又称“微线程”或“纤程”。它在单线程内通过显式的调度点(yield)实现多任务切换,无需内核参与。

特点

特性线程协程
调度内核调度(抢占式)用户态调度(协作式)
上下文切换开销高(进入内核,保存/恢复寄存器、内核栈)低(仅保存/恢复少量寄存器和用户栈指针)
通信共享内存需锁、IPC函数调用/Channel/队列 等
并发规模受限于内核线程数数万乃至数十万轻松支持

调度模型

  • 协作式:运行到显式 yieldawait 才切换,开发者可精确控制切换点。
  • 预emptive(部分语言支持):语言运行时定期打断协程,但大多数主流实现(如 Python、Go)采用协作式。

常见实现

  • Go:goroutine + M:N 调度,M 代表系统线程,N 代表用户协程,由 runtime 自动分配。
  • Pythonasync def + await,基于事件循环(asyncio)或第三方库(如 Trio、Curio)。
  • Rustasync/await + Futures + executor(如 Tokio、async-std),通过状态机驱动。
  • JavaScript:基于事件循环的 Promise + async/await,单线程协程模型。

应用场景

  • 高并发 I/O:Web 服务器、爬虫、网络代理等,常用事件驱动 + 协程模型实现百万级并发。
  • 异步任务流:管道化处理、大量小任务的并行调度。
  • 可控并发:无需锁或细粒度锁,简化并发控制。

四者对比与协同

模型调度方式切换开销共享资源适用场景
进程内核(抢占)最大无(需 IPC)资源隔离、强隔离需求
线程内核(抢占)较大共享进程资源CPU 并行、I/O 并发
协程用户(协作)最小共享线程资源海量并发 I/O、异步流程
虚拟地址——————为进程/线程/协程提供统一内存抽象
  • 进程是资源分配的基本单位,每个进程都有独立的内存空间(代码段、数据段、堆栈等),提供最强隔离。
  • 线程是 CPU 调度的基本单位,属于进程,一个进程可以包含多个线程。共享进程的内存空间和资源(文件句柄、数据段等)在同一地址空间内并行。
  • 协程: 在单线程内更高效地调度。
  • 虚拟地址: 是上述模型的基础,屏蔽物理内存复杂性并提供保护。

应用场景选型

场景建议方案
资源隔离优先对安全或稳定性要求极高的组件,首选进程
并行计算CPU 密集任务可用多进程或多线程
高并发 I/O首选协程框架,结合事件驱动(如 epoll、kqueue)
混合模式Web 服务常用 “多进程 + 协程” 的组合:进程隔离,协程高并发

总结

  • 进程线程协程 是三种层次不同的并发单元,各自有取舍。
  • 虚拟地址 为它们提供了统一、隔离且安全的内存视图。
  • 在实际系统设计中,合理组合使用,才能兼顾隔离性、并发性与性能,打造高性能、高可靠的应用架构。

进程调度算法

非抢占式调度

  1. 先来先服务(FCFS)

    • 原理:按进程到达就绪队列的先后顺序依次调度,类似队列排队。
    • 优点:简单易实现;无饥饿。
    • 缺点:平均等待时间不一定最短,易出现“短作业后面跟长作业”拖慢整体效率。
  2. 短作业优先(SJF)/最短剩余时间优先(SRTF)

    • SJF(非抢占):每次选择执行时间最短的作业;
    • SRTF(抢占):新作业到达时,如果其所需时间比当前剩余时间短,则抢占。
    • 优点:能最小化平均等待时间;
    • 缺点:需要准确估计执行时间;可能导致长作业“饥饿”。
  3. 优先级调度(Priority)

    • 原理:为每个进程分配优先级,优先级高的先执行;可抢占或非抢占。
    • 优点:满足关键任务优先执行;
    • 缺点:低优先级可能长时间得不到调度(饥饿),需用“优先级老化”机制解决。

抢占式调度

  1. 时间片轮转(Round Robin,RR)

    • 原理:给每个进程分配固定长度的时间片,时间片用完即切换到下一个进程,循环往复。
    • 优点:响应时间可控,适合交互式系统;无进程饥饿。
    • 缺点:时间片大小需平衡,过大接近 FCFS,过小切换开销大。
  2. 多级队列调度(Multilevel Queue)

    • 原理:将进程按类型(交互式、批处理、系统进程等)分到多个队列,不同队列使用不同算法和优先级。
    • 优点:可针对性地优化不同类型作业;
    • 缺点:队列间切换策略固定,灵活性较差。
  3. 多级反馈队列(Multilevel Feedback Queue)

    • 原理:允许进程在不同优先级队列间动态升降,根据其执行特性(CPU 密集或 I/O 密集)调整优先级。
    • 优点:兼顾短作业和长作业,能自动提升响应性;
    • 缺点:参数(队列数、时间片长度、反馈规则)较多,需要调优。

现代与实时调度

  1. 最早截止时间优先(EDF, Earliest Deadline First)

    • 应用:实时系统
    • 原理:总是选择截止时间最早的任务执行,可抢占。
    • 优点:理论上能在系统总利用率 ≤100% 时保证所有任务准时完成;
    • 缺点:需要精确的任务截止时间。
  2. 率先最小周期优先(RMS, Rate Monotonic Scheduling)

    • 应用:实时系统,周期性任务
    • 原理:周期短(率高)的任务优先级高;
    • 优点:简单固定优先级;
    • 缺点:在高利用率下不能保证可调度(理论上利用率上限 ≈69%)。
  3. Linux 完全公平调度器(CFS, Completely Fair Scheduler)

    • 应用:通用 Linux 桌面/服务器
    • 原理:用虚拟运行时间(vruntime)衡量每个任务已经“拿过”的 CPU 时间,优先选择 vruntime 最小者执行。
    • 优点:可以在多任务间实现近似理想的公平;
    • 缺点:算法复杂度高于传统调度,切换开销略大。

选择与权衡

  • 交互式系统(桌面应用、Web 服务器):优先 RR、Multilevel Feedback Queue、CFS
  • 批处理系统(后台任务、科学计算):可选 SJF/SRTF、Multilevel Queue
  • 实时系统(控制、嵌入式):EDF、RMS
  • 混合场景:多级反馈队列 + 结合优先级老化保证低优先级可执行
算法抢占优点缺点
FCFS简单易实现,无饥饿平均等待时间高
SJF / SRTF可选最小化平均等待时间需估计运行时长;长期作业易饥饿
Priority可选可满足关键任务优先需防止低优先级饥饿
Round Robin响应时间可控,无饥饿时间片选取需平衡;频繁切换开销大
Multilevel Queue可选针对不同类型作业优化队列间固化策略;灵活性差
Multilevel Feedback自适应调度,兼顾短/长作业参数调优复杂
EDF / RMS(实时)实时可调度保证需准确的任务参数
CFS理想公平,适合通用场景实现复杂,切换开销略大
想都是问题,做才是答案!
使用 Hugo 构建
主题 StackJimmy 设计