线程
线程的概念
引入线程
- 线程是进程的一部分,具有一段执行流
- 线程在同一个进程的地址空间内,可以共享变量
- 线程是CPU调度的基本单位
进程 VS 线程
进程:
- 运行时:代码、寄存器、堆栈、数据段
- 资源:地址空间、文件描述符、权限等
最简单的进程只有一个线程
地址空间
- 进程之间不共享内存
- 进程切换会切换页表
- 进程中的线程共享整个地址空间
权限
- 进程拥有自己的权限(如文件访问权限)
- 进程中的线程共享所有的权限
过程 VS 线程
过程调用
s0/fp/指向栈底,sp指向最新的栈顶- 被调用者将函数参数压栈
- 被调用者将局部变量压栈

线程调用
- 多线程并发执行
- 多线程可以并行地在多个CPU上运行
- 过程调用是顺序的
- 线程可能会乱序地执行
- 不能利用栈恢复过程
- 每一个线程都有自己的栈
- 线程不能频繁的切换
- 每一个线程通常绑定一个CPU的核
线程并发性/并行性
- 人们希望同时完成多件事情(服务器需要同时服务多个请求)
- 计算交叠、I/O交叠(不同的线程使用不同的资源)
- 多个线程共享内存,但会带来共享资源访问问题
线程表示与操作API
线程控制块(TCB)
- 状态
- 就绪态:准备运行
- 运行态:正在运行
- 阻塞态:等待资源
- 寄存器
- 程序计数器(PC)
- 栈
- 代码
典型的线程API
创建
create,join
互斥
acquire,release
条件变量
wait,signal,broadcast
警报
alert,alertwait,testalert
线程上下文切换
- 保存上下文
- 所有的寄存器(通用寄存器和浮点寄存器)
- 所有协处理器的状态
- 开始新的上下文
- 做保存上下文的逆操作
- 可能触发进程的上下文切换
- 单线程操作
- 执行I/O操作
保存上下文
- 在线程的栈上保存上下文
- 可以利用处理器专用的指令进行高效的保存
- 保存前需要确保栈上没有溢出的问题
- 在
TCB中保存上下文- 不存在溢出问题,但效率可能不是很高
线程模型
分类
- 用户级线程
- 内核级线程
- 轻量级线程
分类依据(核内调度 VS 核外调度)
- 核外调度:减少上下文切换开销
- 核内调度:充分利用SMP结构
用户级线程(协程)
由一组用户级的线程库函数来完成线程的管理, 包括线程的创建、终止、同步和调度等

内核级线程
直接由内核本身启动的工作线程,执行内核函数
特点
- 在CPU特权级中运行
- 访问内存的内核地址空间
轻量级线程(LWP)
特点
- 共享某些资源的进程,例如地址空间、打开文件等资源
- 实现内核支持的线程机制

模式一
用户空间线程映射到一个LWP上(Linux)

模式二
多个用户空间线程映射到多个LWP上(Solaris,Unix,System V)

用户级线程 VS LWP
- 用户级线程
- 用户级线程库实现线程上下文切换
- 时间中断会引入抢占
- 当用户级线程被I/O事件阻塞时,整个进程都会被阻塞
- LWP
- LWP被内核调度器调度
- 由于跨越了用户态和内核态,LWP的上下文切换开销大于用户级线程

不同映射关系的对比
- 一对一:每一个线程都拥有自己的内核栈
- 多对一:一个进程的所有线程共享同一个内核栈
- 多对多:多个线程共享一个内核栈
| 一对一 私有的内核栈 |
多对多 共享的内核栈 |
多对一 共享的内核栈 |
|
|---|---|---|---|
| 内存消耗 | 高 | 中 | 低 |
| 系统服务 | 并发 | 部分并发 | 串行访问 |
| 多处理器 | 是 | 部分利用 | 无法利用 |
| 内核复杂性 | 高 | 高 | 低 |