跳转至

Threads

引入进程的目的是更好地使多道程序并发执行,提高资源利用率和系统吞吐量;而引入线程的目的则是减小程序在并发执行时所付出的时空开销,提高操作系统的并发性能。

线程最直接的理解是“轻量级进程”,是一个基本的CPU执行单元,也是程序执行流的最小单元,由 线程ID、程序计数器、寄存器集合和堆栈 组成

在多线程进程中,需要寄存器和栈为每一个线程进维护。

  • Benefits:
    1. 响应性:交互式应用程序。
    2. 资源共享:用于代码和数据的内存可以共享。
    3. 经济:创建进程更昂贵(需要分配资源),而创建线程能节约资源。
    4. MP架构的利用:多线程提高了并发性。

线程的实现方式

线程的实现可以分为两类:用户级线程和内核级线程。

  • 用户级线程:“从用户视角能看到的线程”,有关线程管理的所有工作都由应用程序在用户空间内完成,内核意识不到线程的存在。
    * 优点:
    1. 线程切换不需要转换到内核空间,节省开销
    2. 调度算法可以是某个进程专用的,各个进程可针对自身情况选择合适的调度算法
    3. 与操作系统平台无关,对线程管理的代码属于用户程序的一部分
  • 内核级线程:在内核的支持下运行,线程管理的所有工作在内核空间内实现。
    * 优点:
    1. 能发挥多CPU的优势
    2. 如果进程中的一个线程被阻塞,内核可以调度该进程中的其他线程占用CPU,也可以运行其他进程中的线程
    3. 内核支持线程具有很小的数据结构和堆栈,线程切换快、开销小
    4. 内核本身也可采用多线程技术,可以提高系统的执行速度和效率

Multithreading Models

在同时支持用户级线程和内核级线程的系统中,由于用户级线程和内核级线程连接方式不同,形成了以下三种不同的多线程模型:

Many-to-One

线程管理是有效的,但是如果进行系统调用会阻塞,内核一次只能调度一个线程

One-to-One

更高的并发性,但创建线程的成本很高

Many-to-Many

灵活的

Two-level Model

Threading Issues

  • fork()只复制调用线程还是复制所有线程?
    1. 一些unix系统有两个版本的fork(),一个复制所有线程,另一个复制调用fork()的线程。
    2. Exec()将替换整个进程。
  • Thread Cancellation:在线程完成之前终止它,两种一般方法:
    1. Asynchronous cancellation(异步取消):立即终止目标线程。可能导致泄露和不一致
    2. Deferred cancellation(延迟取消):允许目标线程通过标志定期检查是否应该取消。
  • Signal Handling
    * 在UNIX系统中,信号用于通知进程某个特定事件已经发生

    * 信号处理程序用于处理同步或异步信号:
    1. 信号是由特定事件产生的
    2. 信号被传送到一个进程
    3. 信号被处理
    * Options:(传送方式依讯号类型而定)
    1. 将信号传递给应用该信号的线程
    2. 将信号传递给进程中的每个线程
    3. 将信号传递给进程中的某些线程
    4. 指定一个特定的线程来接收进程的所有信号

  • Thread Pools:在一个线程池中创建一些等待工作的线程
    * 优点:
    1. 使用现有线程处理请求通常比创建新线程快一些
    2. 允许将应用程序中的线程数绑定到池的大小
  • Thread Specific Data(TLS)
    1. 允许每个线程拥有自己的数据副本
    2. 在某些方面类似于静态数据,但对每个线程都是唯一的
    3. 当无法控制线程创建过程时(例如使用线程池时)非常有用。