一、概述
多线程一词可以解释为多个控制线程或多个控制流。虽然传统的UNIX 进程包含单个控制线程,但多线程(multithreading, MT) 会将一个进程分成许多执行线程,其中每个线程都可
独立运行。多线程编程的概念至少可以回溯到二十世纪六十年代。多线程编程在UNIX 系统中的发展是从八十年代中期开始的。虽然对多线程的定义以及对支持多线程所需要的功能存在共识,但是用于实现多线程的接口有很大不同。
二、多线程的益处
1、提高应用程序的响应
可以对任何一个包含许多相互独立的活动的程序进行重新设计,以便将每个活动定义为一个线程。例如,多线程GUI 的用户不必等待一个活动完成即可启动另一个活动。
2、有效使用多处理器
通常,要求并发线程的应用程序无需考虑可用处理器的数量。使用额外的处理器可以明显提高应用程序的性能。具有高度并行性的数值算法和数值应用程序(如矩阵乘法)在多处理器上通过多个线程实现时,运行速度会快得多。
3、改进程序结构
许多应用程序都以更有效的方式构造为多个独立或半独立的执行单元,而非整块的单个线程。多线程程序比单线程程序更能适应用户需求的变化。
4、占用较少的系统资源
如果两个或多个进程通过共享内存访问公用数据,则使用这些进程的程序可以实现对多个线程的控制。但是,每个进程都有一个完整的地址空间和操作环境状态。每个进程用于创建和维护大量状态信息的成本,与一个线程相比,无论是在时间上还是空间上代价都更高。
此外,进程间所固有的独立性使得程序员需要花费很多精力来处理不同进程间线程的通信或者同步这些线程的操作。
特别说明:结合线程和RPC(远程过程调用)
通过将多个线程和一个远程过程调用(remote procedure call, RPC) 结合起来,可以充分利用无共享内存的多处理器(如工作站集合)。这种结合将工作站集合视为一个多处理器,从而使应用程序的分布变得相对容易些。
例如,一个线程可以创建多个子线程,每个子线程随后可以请求远程过程调用,从而调用
另一个工作站上的过程。尽管初始线程此时仅创建了一些并行运行的线程,但是这种并行
性会涉及到其他计算机。
三、多线程概念
1、并发性和并行性
在单个处理器的多线程进程中,处理器可以在线程之间切换执行资源,从而执行并发。在共享内存的多处理器环境内的同一个多线程进程中,进程中的每个线程都可以在一个单
独的处理器上并发运行,从而执行并行。如果进程中的线程数不超过处理器的数目,则线程的支持系统和操作环境可确保每个线程在不同的处理器上执行。例如,在线程数和处理器数目相同的矩阵乘法中,每个线程和每个处理器都会计算一行结果。
创建线程比创建新进程成本低,因为新创建的线程使用的是当前进程的地址空间。相对于在进程之间切换,在线程之间进行切换所需的时间更少,因为后者不包括地址空间之间的切换。
2、用户级线程
线程是多线程编程中的主编程接口。线程仅在进程内部是可见的,进程内部的线程会共享诸如地址空间、打开的文件等所有进程资源。
用户级线程状态:
以下状态对于每个线程是唯一的。
- 线程ID
- 寄存器状态(包括PC 和栈指针)
- 栈
- 信号掩码
- 优先级
- 线程专用存储
3、线程调度
POSIX 标准指定了三种调度策略:先入先出策略(SCHED_FIFO)、循环策略(SCHED_RR) 和自定义策略(SCHED_OTHER)。SCHED_FIFO 是基于队列的调度程序,对于每个优先级都会使用不同的队列。SCHED_RR 与FIFO 相似,不同的是前者的每个线程都有一个执行时间配额。
SCHED_FIFO 和SCHED_RR 是对POSIX Realtime 的扩展。SCHED_OTHER 是缺省的调度策略。
提供了两个调度范围:进程范围(PTHREAD_SCOPE_PROCESS) 和系统范围(PTHREAD_SCOPE_SYSTEM)。具有不同范围状态的线程可以在同一个系统甚至同一个进程中共存。进程范围只允许这种线程与同一进程中的其他线程争用资源,而系统范围则允许此类线程与系统内的其他所有线程争用资源。
4、线程取消
一个线程可以请求终止同一个进程中的其他任何线程。目标线程(要取消的线程)可以延后取消请求,并在该线程处理取消请求时执行特定于应用程序的清理操作。
5、线程同步
使用同步功能,可以控制程序流并访问共享数据,从而并发执行多个线程。
共有四种同步模型:互斥锁、读写锁、条件变量和信号。
- 互斥锁仅允许每次使用一个线程来执行特定的部分代码或者访问特定数据。
- 读写锁允许对受保护的共享资源进行并发读取和独占写入。要修改资源,线程必须首先获取互斥写锁。只有释放所有的读锁之后,才允许使用互斥写锁。
- 条件变量会一直阻塞线程,直到特定的条件为真。
- 计数信号量通常用来协调对资源的访问。使用计数,可以限制访问某个信号的线程数量。达到指定的计数时,信号将阻塞。