基本概念

进程=进程上下文(处理器上下文+内核上下文)+虚存 进程=线程+代码段+数据段+内核上下文

一个进程可以关联多个线程

  • 每个线程有自己的处理器上下文
  • 共享代码段、数据段和内核上下文
  • 有自己的线程编号

线程 vs 进程

相同点:

  • 都有自己的控制流
  • 都能并发运行
  • 都有上下文切换 不同点:
  • 线程共享代码和数据,而进程通常不会
  • 线程的资源开销比进程小
  • 与进程相关的线程组成一个线程池,而父子进程间形成树状结构

线程 vs 协程

  • 线程由 OS 管理,协程由程序本身管理
  • 协程的资源开销比线程小
  • 在多核 CPU 上,线程可以实现并行,而协程本身不实现并行

使用线程的优点:

  • 易于在线程间共享数据
  • 比进程更有效率 缺点:共享容易出错

共享

  • 线程的内存模型是什么?
  • 变量实例是如何映射到内存的?
  • 有多少线程引用这些实例? 一个变量是共享的,当且仅当有多个线程引用这个实例。

线程内存模型

每个线程有独立的线程上下文,所有线程共享其余进程资源。

  • 寄存器总是严格隔离并受到保护的,但虚存不是
  • 任何线程可以读写其他任何线程的栈

将变量实例映射到内存

  • 全局变量:虚存中只包含一个实例
  • 局部变量:每个线程栈中包含一个实例
  • 局部静态变量:虚存中只包含一个实例

互斥

任何顺序一致的交错执行都是可能的。

进度图: 个线程的执行模型化为一条 维直角坐标系中的轨迹,每条轴对应一个线程中指令的执行顺序,每个点对应一个可能状态。 临界区:临界区中的指令(读写共享变量)不应该交错 两个临界区的交集形成的空间区域称为不安全区。 若轨迹没有进入不安全区,则它是安全的

信号量

信号量 是具有非负整数值的全局变量,只能由两类操作处理:

  • :如果 是非零的,则将 减一并返回,否则挂起这个线程
  • :将 加一,如果有线程阻塞在 ,则选取其中一个重启
int sem_init(sem_t *sem, 0, unsigned int value);
int sem_wait(sem_t *s); // P
int sem_post(sem_t *s); // V

用信号量实现互斥

每个共享变量与一个信号量 (初始为 1)联系起来,用 将相应的临界区包围起来。

用信号量调度共享资源

生产者&消费者:生产者等待空闲的 buffer,消费者等待 item

死锁

如何避免?

  • 不同线程以相同顺序获得锁