几乎所有现代操作系统都允许一个进程包含多个线程。每个线程是 CPU 使用的一个基本单元,它包括线程 ID、程序计数器、寄存器组和堆栈。
进程与同一进程的其他线程共享代码段、数据段和其他操作系统资源,如打开文件和信号。每个传统或重量级进程只有单个控制线程。如果一个进程具有多个控制线程,那么它能同时执行多个任务。
图 1 说明了传统单线程进程和多线程进程的差异。
现代计算机运行的大多数应用软件都是多线程的。一个应用程序通常作为具有多个控制线程的一个进程来实现。
例如,一个 Web 浏览器可能有一个线程来显示图像和文本,另一个线程从网络接收数据。一个字处理器可能有一个线程用于显示图形,另一个线程用于响应用户的键盘输入,还有一个线程在后台进行拼写和语法检查。应用程序也可以设计成利用多核系统的处理能力。这些应用程序可以在多处理核上并行执行多个 CPU 密集型的任务。
在有些情况下,单个应用程序可能需要执行多个类似任务。例如,一个 Web 服务器接收有关网页、图像、声音等的客户请求。一个繁忙 Web 服务器可能有多个(可能数千个)客户并发访问它。如果一个 Web 服务器作为单个线程的传统进程来执行,那么只能一次处理一个请求;这样,客户可能需要等待很长时间,以便请求得到处理。
一种解决方法是让服务器作为单个进程运行以便接收请求。当服务器收到请求时,它会创建另一个进程以便处理请求。事实上,这种进程创建方法在线程流行之前很常见。不过,进程创建很耗时间和资源。如果新进程与原进程执行同样的任务,那么为什么要承担所有这些开销?
通常,使用一个包含多个线程的进程更加有效。如果 Web 服务器进程是多线程的,那么这种服务器可以创建一个单独线程,以便监听客户请求。当有请求时,服务器不是创建进程而是创建线程以处理请求,并恢复监听其他请求,见图 2。
线程在远程过程调用(RPC)系统中,也起着至关重要的作用。RPC 通过提供一种类似于普通函数或子程序调用的通信机制,以允许进程间通信。
通常,RPC 服务器是多线程的。当一个服务器收到消息时,它使用一个单独线程来处理消息。这允许服务器处理多个并发请求。
最后,大多数的操作系统内核现在都是多线程的。多个线程在内核中运行,每个线程执行一个特定任务,如管理设备、管理内存或处理中断。例如,Solaris 有一组内核线程以处理中断,Linux 采用一个内核线程以便管理系统空闲内存的数量。
多线程编程具有如下四大类的优点: