操作系统原理第四章:线程

1 线程的引入

1.1 线程的由来

前面章节提到,引入进程是为了解决程序并发所出现的一些问题,进程具有两个基本的属性:

  • 进程是一个拥有资源的独立单位:它可独立分配虚地址空间、主存和其它;
  • 进程是一个可独立调度和分派的基本单位。

正是因为进程具有这两个基本属性,所以进程成为并发执行的基本单位, 在一些早期的OS中,比如大多数UNIX系统、Linux等,进程同时具有这二个属性,由于 进程是一个资源的拥有者 ,因而在进程创建、撤销、调度切换时,系统需要付出较大的时空开销,所以进程的数目不宜过多,进程切换频率不宜过高,否则会限制并发程度,操作系统的设计目标是提高并发度,减小系统开销,显然进程还不能做到完全的高效,所以引入了线程的概念。

那么有没有一种方法能够既提高系统并发,还能减少系统开销呢,我们采用的方法是将进程的两个基本属性分开,对于拥有资源的基本单位,不对其进行频繁切换,对于调度的基本单位,不作为拥有资源的单位,“轻装上阵”,引入线程以小的开销来提高进程内的并发程度。

在没有引入线程之前,进程作为资源分配单位(存储器、文件)和CPU调度单位。当引入线程后把线程作为作为CPU调度单位,而进程只作为其他资源分配单位。相比进程,线程只拥有必不可少的资源,如:线程状态、程序计数器、寄存器上下文和栈,线程同样具有就绪、阻塞和执行三种基本状态,一个进程可以创建多个线程,线程与同属一个进程的其它线程共享进程拥有的全部资源,并且这些线程可以并发执行。

1.2 线程的特点

减小并发执行的时间和空间开销(线程的创建、退出和调度),因此容许在系统中建立更多的线程来提高并发程度,因为线程有如下特点:

  • 线程的创建时间比进程短;
  • 线程的终止时间比进程短;
  • 同进程内的线程切换时间比进程短;
  • 由于同进程内线程间共享内存和文件资源,可直接进行不通过内核的通信;
  • 一个多线程的应用在执行中,即使其中的某个线程阻塞,其他的线程还可继续执行,从而提高响应速度
  • 同一进程的多个线程共享该进程的内存等资源
  • 创建和切换线程的开销要低于进程。比如,Solaris中进程创建时间是线程创建的30倍,进程切换时间是线程切换的5倍
  • 多线程更适用于多处理机结构

1.3 线程的定义

线程(轻型进程)是CPU运用的一个基本单元,包括:

  • 程序计数器 (program counter)
  • 寄存器集 (register set)
  • 栈空间 (stack space)

一个线程与它的对等线程共享如下内容:

  • 代码段 (code section)
  • 数据段 (data section)
  • 操作系统资源 (operating-system resources)

传统的或重型进程等价于只有一个线程的任务,下图是单线程和多线程的对比,可以从图中看到多个线程共享code,data,files,并且每个线程有自己的registers,stack
在这里插入图片描述

1.4 进程和线程的比较

  • 并发性:在引入线程的OS中,不仅进程之间可以并发执行,而且在一个进程中的多个线程之间亦可并发执行,因而使OS具有更好的并发性,从而能更有效地使用系统资源和提高系统吞吐量;
  • 拥有资源:进程是拥有资源的独立单位,而线程只拥有一些必不可少的资源;
  • 系统开销:在创建或撤消进程时,系统都要为之分配或回收资源,如内存空间、I/O设备等。因此,OS所付出的开销将明显地大于在创建或撤消线程时的开销;
  • 地址空间和其他资源(如打开文件):进程间相互独立,同一进程的各线程间共享,某进程内的线程在其他进程不可见;
  • 通信:进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信,需要进程同步和互斥手段的辅助,以保证数据的一致性;
  • 调度:线程上下文切换比进程上下文切换要快得多,下图是线程切换和进程切换的示意图,当单线程进程需要切换的时候,整块内容都需要切换,当多线程进行切换的时候,只需要切换单个线程内容,即虚线框内的内容。
    在这里插入图片描述

2 内核线程和用户线程

线程是一个轻型的进程,引入线程是为了进一步提高系统并发,从而提高系统效率,线程在实现的时候分为两种:

  • 内核支持的线程 (Kernel-supported threads)
  • 用户级线程 (User-level threads):在内核之上,通过用户级的库调用

2.1 内核线程

内核线程由内核支持,在内核空间执行线程创建、调度和管理,当线程是内核线程时,才真正的是CPU调度的基本单位,这么说是因为后面要讲到的用户线程并不是CPU调度的基本单位。内核线程是依赖于操作系统的,这个时候内核维护进程和线程的上下文信息,线程切换由内核完成,一个线程发起系统调用而阻塞,不会影响其他线程的运行,时间片分配给线程,所以多线程的进程获得更多CPU时间(线程作为CPU调度的基本单位,每个线程都会分得时间片,所以线程越多的进程,分到的CPU时间越多)。

2.2 用户线程

用户线程是由用户级线程库进行管理的线程,这个时候线程库提供对线程创建\调度和管理的支持,无需内核支持,因此用户线程不是CPU调度的基本单位,此时进程是CPU调度的基本单位。

由于用户线程不依赖于 OS 核心,应用进程利用线程库提供创建、同步、调度和管理线程的函数来控制用户线程。调度由应用软件内部进行,通常采用非抢先式和更简单的规则,也无需用户态核心态切换,所以速度特别快 。

用户线程的维护由应用进程完成,内核不了解用户线程的存在,用户线程切换不需要内核特权,用户线程的缺点是如果内核是单线程的,那么一个用户线程发起系统调用而阻塞,则整个进程阻塞,此时时间片分配给进程,多线程则每个线程就慢。

2.3 两者比较

  • 调度方式:内核线程的调度和切换与进程的调度和切换十分相似,用户线程的调度不需OS的支持;
  • 调度单位:用户线程的调度以进程为单位进行,在采用时间片轮转调度算法时,每个进程分配相同的时间片。对内核级线程,每个线程分配时间片

3 线程模型

用户线程是在用户空间去实现的,有关于用户线程的所有操作都是在用户空间里实现的,那么这样的用户线程如果要用到操作系统提供的功能的时候,它通常是要映射到内核空间去,就要在用户线程和内核线程之间做映射,在映射过程中有以下三种模式:

  • 多对一 (Many-to-One):多个用户线程映射到内核线程上,如下图,任一时刻只能有一个线程可以访问内核(并发性低),一个用户线程发起系统调用而阻塞,则整个进程阻塞:
    在这里插入图片描述
  • 一对一 (One-to-One):每个用户线程对应一个内核线程,如下图,提供了更好的并发性,一个用户线程发起系统调用而阻塞时允许另一个线程运行,每创建一个用户级线程需创建一个相应的内核线程,带来了额外开销,所以许多系统限制应用中的线程数目:
    在这里插入图片描述
  • 多对多 (Many-to-Many):为了克服上述两种方式的缺点,引入了多对多模型,不限制应用的线程数、多个线程可以并发,如下图:
    在这里插入图片描述
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值