进程的引入
进程有两个很严重的问题:
-
进程在没有得到CPU运行时,进程携带它拥有的资源(包括程序和数据)在内存中就绪或阻塞,占据大量的内存空间;
-
进程在执行过程中如果阻塞,则整个进程就将挂起,而无法继续执行。
进程具有两个基本属性:其一,进程是一个拥有资源的独立单元;其二,进程是一个被处理机独立调度的单元。为了解决进程在未得到调度时携带者繁重的资源在内存就绪或阻塞,引入了线程完成进程的第二个属性,进程只完成第一个属性。即线程是参与处理机调度的单元,参与调度时本身不携带资源,只携带一些必要的信息,得到调度时再从进程处获得资源,因此线程也称为轻型进程
(Light-Weight Process, LWP),而进程携带运行时的全部资源,在未得到运行时,携带着资源的进程可以在外存就绪或阻塞,这样可以节省大量内存空间,利用提高系统的运行效率。所以此时的进程也叫重型进程
(Heavy-Weight Process, HWP)。
线程
(Thread)是进程内的一个相对独立的、可独立调度和指派的执行单元。线程是进程的分身,是进程的不同执行系列。在线程模式下,一个进程至少有一个线程,但也可以有多个线程。
线程管理的基础就是要维持线程的各种信息,存放这些信息的结构称为线程控制块TCB。线程共享一个进程空间,许多资源是共享的。如果某资源不独享会导致线程运行错误,则该资源就由每个线程独享;而其他资源都由进程里面的所有线程共享。
# 线程共享与独享资源的划分
线程共享资源:地址空间、全局变量、打开的文件、子进程、闹铃、信号及信号服务程序
线程独享资源:通用寄存器、指令计数器、程序状态字、栈指针
线程控制块里存放的一般是线程独享的资源和信息,一般的进程控制块主要包含线程标识信息、处理机状态信息(现场信息)、线程调度信息三类。
# 线程控制块的主要内容
线程标识信息:进程号
处理机状态信息(线程信息):通用寄存器、指令计数器、程序状态字、栈指针
线程调度信息:线程状态、线程优先数、等待原因、调度算法参数等
线程也有若干种状态,如运行状态、阻塞状态、就绪状态和终止状态。
线程控制有以下四种:
-
线程创建。一个线程通过调用过程库中的thread_create可以创建新进程。
-
线程终止。一个线程完成自己的工作后,通过调用程序库中的thread_exit终止自身。
-
线程等待。在某些线程系统中,一个线程通过调用程序库的thread_wait可以等待指定线程终止。
-
线程让权。当一个线程自愿放弃CPU,让给另外的线程运行时,它可调用过程thread_yield。
线程与进程的区别:
-
在调度方面,线程是调度和指派的基本单位,而进程是资源拥有的基本单位。在同一进程中,线程的切换不会引起进程切换。在不同的进程中进行线程切换,如一个进程内的线程切换到另一个进程中的线程时,将会引起进程切换。
-
在拥有资源方面,线程不拥有系统资源,但可以访问其隶属进程的系统资源,从而获得系统资源。
-
在并发性方面,在引入线程的操作系统中,不仅进程之间可以并发执行,而且同一进程内的多线程之间也可并发执行,从而使操作系统具有更好的并发性,大大提高系统的吞吐量。
-
在系统开销方面,进程切换时的时空开销很大,但线程切换时,只需保存和设置少量寄存器的内容,因此开销很小。
另外,由于同一进程内的多个线程共享进程的相同地址空间,因此,多线程之间的同步与通信非常容易实现,甚至无需操作系统内核的干预。
引入线程的好处:易于调度、提高并发性、开销少、利于充分发挥多处理器的功能。
线程的实现方式
既然线程是进程的构成部分,或者是进程的分身,那么由谁来管理线程就有两种选择:让进程自己来管理线程、让操作系统来管理线程。这种不同的选择就出现了内核态线程和用户态线程,这也是线程实现的两种方式。由进程自己管理就是用户态线程实现,由操作系统管理就是内核态线程实现。而进程的实现只能由操作系统内核来进行,不存在用户态实现的情况。
内核态线程实现
操作系统要管理线程,就要保持维护线程的各种资料,即将线程控制块存放在操作系统内核空间。这样,操作系统内核就同时保持进程控制块和线程控制块。而根据进程控制块和线程控制块提供的信息,操作系统就可以对线程进行各种类似进程的管理,如线程调度、线程的资源分配、各种安全措施的实现等。
由操作系统来管理线程的好处:
-
用户编程简单。因为线程的复杂性由操作系统承担,用户程序员在编程时无须管理线程的调度。
-
如果一个线程执行阻塞操作,操作系统可以从容地调度另外一个线程执行。因为操作系统能够监控所有的线程。
但是内核态线程实现还是存在一些缺点:效率较低、内核态实现要占用内核稀缺的内存资源、内核态实现需要修改操作系统。
用户态线程实现
用户自己写一个执行系统作调度器(Runtime Scheduler),即除了正常执行任务的线程外,还有一个专门负责线程调度的线程。由于大家都在用户态下运行,谁也不比谁占优势,要想取得CPU控制权只能靠大家的自愿合作。一个线程在执行完一段事件后主动把资源释放给别人使用,而在内核态下则无须如此。因为操作系统可通过周期性的时钟中断把控制权夺过来。在用户态实现情况下,执行系统的调度器也是线程,没有能力强行夺走控制权,所以必须合作。
用户态线程实现的优点:
-
灵活性。因为操作系统不用知道线程的存在,所以在任何操作系统上都能应用。
-
线程切换快,因为切换在用户态进行,无须陷入内核态。
-
不用修改操作系统,实现容易。
用户态实现无法完全达到线程提出所要达到的目的:进程级多道编程。如果在执行过程中一个线程受阻,它将无法将控制权交出去(因为受阻后无法执行交出CPU的指令了),这样整个进程都无法推进。操作系统随即把CPU控制权交给另外一个进程。这样一个线程受阻造成整个进程都受阻,通过线程对进程实施分身的计划就失败了。
混合态线程实现
用户态的执行系统负责进程内部线程在非阻塞时的切换;内核态的操作系统负责阻塞线程的切换,即同时实现内核态和用户态线程管理。其中内核态线程数量较少,而用户态线程数量多。每个内核态线程可以服务一个或多个用户态线程。换句话说,用户态线程被多路复用到内核态线程上。在分配线程时,可将需要执行阻塞操作的线程设为内核态线程,而不会执行阻塞操作的线程设为用户态线程。这样就可以获得两种态势实现下的优点,而避免其缺点。实现混合方式有不同的模型,即多对一模型、一对一模型、多对多模型。
(最近更新:2019年09月18日)