13. 多处理器编程:从入门到放弃

在 UNIX 有了基础的系统调用 API (进程、地址空间、对象访问) 之后随即爆火,新的需求也随之而来,例如进程在 read() 等操作等待 I/O 时可能还可以同时完成其他任务,以及硬件逐渐有了多个 CPU 处理器……进程级的并行显得有些 “不太够用”。我们需要一个新的机制,能让多个执行流共享内存——于是就有了线程。

本讲内容:多线程编程模型、线程库,以及现代多处理器系统上的并发编程为什么困难。

13.1 入门:共享内存线程模型与线程库

在我们的 thread.h 是用 POSIX Threads (pthread) 实现的。pthread 支持配置线程栈、将线程从 main 函数中 “分离” 出去,不在 main 返回后被杀死等功能,手册包含了它的功能。Linux 操作系统提供了 clone() 等系统调用实现 POSIX Threads API。

13.2 放弃 (1)

💡并发编程确实有诸多好处
那么,代价是什么呢?代价就是我们需要重新理解 “编程”。

    13.3 放弃 (2)

    13.4 放弃 (3)

    12.4 总结

    Take-away Messages: 我们可以很容易地把状态机模型扩展为共享内存上的多线程模型——只是每次选择一个状态机执行一步,通过提供 spawn 和 join 两个 API 来利用现有多处理器系统的共享内存能力。

    然而,由于编译优化的 “无处不在” (处理器也是编译器),共享内存并发的行为十分复杂。与此同时,人类又恰好是物理世界 (宏观时间) 中的 “sequential creature”,编程语言的直觉 (顺序/选择/循环结构) 也是围绕顺序程序设计,因此共享内存上的并发编程是非常具有挑战性的 “底层技术”。在《操作系统》课中,我们不建议大家 “玩火”——我们之后会介绍多种并发控制技术,使得我们可以在需要的时候避免并发的发生,使并发程序退回到顺序程序,从而使我们能够理解和控制并发。

    课后习题/编程作业

    📚阅读材料

    教科书 Operating Systems: Three Easy Pieces:

    • 第 25 章 - Dialogue on Concurrency
    • 第 26 章 - Concurrency and Threads
    • 第 27 章 - Thread API