Three Easy Pieces: 并发

操作系统作为 “状态机的管理者”,引入了共享的状态

  • 带来了并发
  • (操作系统是最早的并发程序)

def Tprint(name):
    sys_write(f'{name}')

def main():
    for name in 'AB':
        sys_spawn(Tprint, name)
  • 使用 model checker 绘制状态图

多线程共享内存并发

线程:共享内存的执行流

  • 执行流拥有独立的堆栈/寄存器

简化的线程 API (thread.h)

  • spawn(fn)
    • 创建一个入口函数是 fn 的线程,并立即开始执行
      • void fn(int tid) { ... }
      • 参数 tid 从 1 开始编号
    • 行为:sys_spawn(fn, tid)
  • join()
    • 等待所有运行线程的返回 (也可以不调用)
    • 行为:while (done != T) sys_sched()

多线程共享内存并发:入门

多处理器编程:一个 API 搞定

#include "thread.h"

void Ta() { while (1) { printf("a"); } }
void Tb() { while (1) { printf("b"); } }

int main() {
  create(Ta);
  create(Tb);
}
  • 这个程序可以利用系统中的多处理器
    • 操作系统会自动把线程放置在不同的处理器上
    • CPU 使用率超过了 100%

问出更多的问题

TaTb 真的共享内存吗?

  • 如何证明/否证这件事?

如何证明线程具有独立堆栈 (以及确定堆栈的范围)?

  • 输出混乱,应该如何处理?

更多的 “好问题” 和解决

  • 创建线程使用的是哪个系统调用?
  • 能不能用 gdb 调试?
    • 基本原则:有需求,就能做到 (RTFM)

thread.h 背后:POSIX Threads

想进一步配置线程?

  • 设置更大的线程栈
  • 设置 detach 运行 (不在进程结束后被杀死,也不能 join)
  • ……

POSIX 为我们提供了线程库 (pthreads)

  • man 7 pthreads
  • 练习:改写 thread.h,使得线程拥有更大的栈
    • 可以用 stack probe 的程序验证