操作系统:线程
什么是线程?我们为什么要使用线程?
概念上讲,线程与进程比较类似,可以说,线程就是进程中的一条执行流程。对于每个进程下的多个线程,我们可以把它们想象成共享同一个地址空间的多个轻量级进程。这也是我们使用线程的最重要的原因:我们需要一种共享同一个地址空间和可用数据的并行实体。
举一个简单的例子,考虑一个字处理软件(比如word),用户在使用鼠标和键盘进行I/O操作,在I/O操作的同时,进程还需要随时整理文章的格式:例如用户删除了第600页的第一行,600页之后的行数都需要向前移动一行。这种情况下,我们需要一个线程来处理(大部分时间是等待)I/O操作,另一个线程来重排格式。通过多线程并行的方式,字处理软件达到了现在的实时效果。
线程的实现
和进程类似,线程也存在线程控制块(TCB)和线程表。进程控制表存放在内核空间中,需要进行进程操作之前,必须陷入内核态。但线程的实现则不必然。事实上,我们可以把线程表放在内核空间、用户空间中,或者二者均有。
用户线程
用户线程即把所有的线程表都放在用户空间中(如图1所示)。内核只能感知到进程。每个进程都有它自己的线程表,对线程的管理是通过一组用户级的线程函数库,包括线程的创建、终止、同步、调度等。用户线程的切换也无需陷入到内核态中,因此速度特别快。由于每个进程都有自己的调度算法,线程之间的使用也更加灵活。
然而,用户线程也有以下几个问题:
- 难以实现阻塞性的系统调用:操作系统看不到线程,若某个进程中的线程试图发出系统调用而阻塞,那整个进程都会阻塞。
- 当一个线程开始运行后,除非它主动放弃CPU,否则该进程中的其他线程将无法运行。
- 由于时间片是分给进程的,多线程运行时,每个线程的时间片相对较少。
内核线程
与用户线程相反,内核线程即在内核中维护一张线程表,由操作系统的内核来完成线程的创建、终止与管理。内核线程可以解决用户线程的问题,一个线程阻塞的同时,同进程的其他线程仍可以运行;操作系统可以为线程分配时间片,来调节不同线程的运行。
但是,在内核中维护线程表意味着每次对线程的操作都要陷入内核态。这一选择大大增加了系统开销。
混合实现
一种混合实现的方法是使用内核级线程,然后将某些用户级线程与某些或全部内核线程多路复用起来。编程人员可以决定多路复用的具体数目。内核只识别内核级线程并对其进行调度。