《进程是什么》一节讲到,为了提高 cpu 的利用率,便于分配和回收计算机软、硬件资源,多任务操作系统引入了“进程”这个概念。
多任务操作系统中,执行的每个任务(程序)都是一个进程。借助进程调度程序,操作系统可以同时执行多个进程(又称并发执行),每个进程使用的计算机资源都由操作系统负责分配和回收。因此,您可以这样理解进程,它是多任务操作系统分配和回收计算机资源的基本单位。
注意,虽然多任务操作系统支持多个进程并发执行,但实际场景中,某些并发执行的任务并不适合用多进程的方式实现。例如实现一个可接收多个用户访问请求的 web 服务器,为了避免用户等待的时间过长,web 服务器需要并发地处理不同用户发来的请求。
这种情况下,如果以多进程的方式实现该服务器,即为每个用户单独建立一个进程,会产生以下问题:
每创建一个进程,都需要占用较多的内存空间。随着访问服务器的用户数量越多,创建的进程数量就越多,可用的内存空间就越少;
进程的上下文切换是一个复杂的过程,需要消耗大量的系统资源。
因此,创建的进程越多,系统所做的进程上下文切换的次数就越多,消耗的资源就越多,最终导致服务器可以处理的用户请求数量越少。
为了更高效率地解决此类问题,操作系统在“进程”的基础上,又引入了“线程”这个概念。
什么是线程
线程是进程的一部分,又称轻量级进程,它可以执行所属进程中的部分或者全部代码。
进程是操作系统分配和回收计算机资源的基本单位,而真正负责执行程序的是进程中的线程。一个进程至少拥有 1 个线程(又称单线程进程),也可以拥有多个线程,每个线程负责执行不同的任务(又称为多线程进程)。
进程中的每个线程,都拥有自己的程序计数器、寄存器、和堆栈,它们的功能分别是:
程序计数器(counter):跟踪要执行的下一条指令;
寄存器(register):临时存储当前执行的指令需要使用的数据;
堆栈(stack):简称栈,可以存储函数相互调用的过程以及期间用到的数据(例如形式参数、局部变量等)。
下图为您展示了单线程进程和多线程进程的内部结构:
图 1 线程的内部结构
其中,data 表示进程的数据区,files 表示已打开的一些文件资源,它们为整个进程所有,即所有线程共享这些资源。
和每个进程都对应有一个进程控制块(pcb)类似,每个线程也对应有自己的线程控制块(简称 tcb)。tcb 中记录的线程状态数据要比 pcb 少得多。因此创建一个线程消耗的系统资源更少,线程上下文切换的效率更高。
线程的类型
线程的类型有 2 种,分别为用户级线程和系统级线程。
1) 用户级线程
所谓用户级线程,即由用户自己建立的线程,此类线程的管理工作全部由用户自己完成,操作系统只负责管理进程。
为了便于用户管理和使用线程,操作系统提供有一个供用户使用的线程库,借助它,用户可以轻松实现对线程的创建、调度和销毁操作。此外,线程库还提供有线程间通信,线程上下文切换等功能。
注意,用户级线程的上下文切换,仅限于进行线程间的调度,而不会影响 cpu 调度(进程调度)。
2) 系统级线程
系统级线程指的是由操作系统负责管理的线程。操作系统会提供给用户一个调用接口(api),从而使用户可以创建、执行以及销毁线程。
操作系统在负责管理进程调度的同时,还负责管理系统级线程的调度工作。对于同一进程中的多个线程,操作系统可以将其调度到一个 cpu 上并发执行,也可以将其调度到多个 cpu 上并发执行。
对于多用户级线程的进程来说,操作系统只会为该进程分配一个 cpu。
系统级线程上下文切换的效率不如用户级线程,但仍比进程上下文切换的效率高。