当前位置:   article > 正文

线程基本概念 - 进程与线程(三)_进程与线程 导入视频

进程与线程 导入视频

在操作系统中引入进程的目的,是为了使多个程序能并发执行,以提高资源的利用率和系统的吞吐量,那么在操作系统中再引入线程(mini进程),则是为了减少程序在并发执行时所付出的时空开销,使OS具有更好的并发行。本小节主要是学习以下内容

  • 什么是线程,为什么要引入线程
  • 与进程相比,线程有哪些特点
  • 用户线程
  • 内核线程

1. 线程的引入

我们以软件生活中,常见的应用为例,我们要编写一个MP4的播放软件,其核心功能模块有以下三个:

  • 磁盘文件中读取MP4数据
  • 对视频数据进行解码
  • 把解码后的视频数据进行播放
  • 对于目前采用进程的方法,我们可以采取两种方案。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YNvjTQdy-1617541102305)(D:\学习总结\内存管理单元\image-20210404192733502.png)]

1.1. 方案一:单进程的实现方式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xgcFikTr-1617541102307)(D:\学习总结\内存管理单元\image-20210404192932081.png)]

方案存在的问题:

  • 播放的视频是否能够连贯
  • 各个函数之间不是并发执行,影响资源的使用效率

1.2. 方案二:多进程的实现:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W0rMqY5V-1617541102309)(D:\学习总结\内存管理单元\image-20210404193040938.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eR53OnPI-1617541102311)(D:\学习总结\内存管理单元\image-20210404194250941.png)]

存在的问题

  • 进程之间如何通信,如何共享数据
  • 系统开销比较大,创建进程、进程结束、进程切换

对于这三个进程,都是为了完成该软件的某一部分功能,但是功能与功能之间必须并发的执行,当切换进程,需要保存/恢复进程运行环境,还需要切换内存的地址空间,更新块表等开销,所以在进程内部增加了一类实体,这个实体就是线程(Thread),满足以下特性

  • 实体之间可以并发执行
  • 实体之间共享相同的地址空间

我们在回过头去看刚才的例子,其处理过程如下图所示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hU2Qrx4j-1617541102313)(D:\学习总结\内存管理单元\image-20210404194737616.png)]

一个进程可以包含多个线程,不同的线程之间可以执行不同的代码序列,例如,我们的读取视频数据,解码,播放分别为3个线程。引入线程后,线程是CPU调度的基本单位,也就是说现在CPU为各个线程服务。虽然引入了进程,但是进程依然是资源分配的基本单位,从属于统一进程的各个线程共享进程的资源。所以针对以下问题,就需要引入线程的概念

  • 创建进程的开销较大,包括数据、代码、堆、栈等
  • 进程的隔离性过强,进程间交互,可以通过进程间通信IPC,但是开销较大
  • 进程内部无法支持并行

2. 线程的概念

从上面可以看出,线程是进程的一部分,描述指令流执行状态,它是进程中的指令执行流的最小单元,是CPU调度的基本单位。

  • 进程的资源分配:进程是由一组相关资源构成,包括地址空间(代码段、数据段)、打开的文件等各种资源
  • 线程的处理机调度角色: 线程描述在进程资源环境中的指令流执行状态

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WvgyUzfQ-1617541102314)(D:\学习总结\内存管理单元\image-20210404195838064.png)]
从上图可以看出,所以线程 = 进程 - 共享资源。线程的优点

  • 一个进程可以同时存在多个线程
  • 各个线程之间可以并发执行
  • 各个线程之间可共享地址空间和文件等资源

线程的缺点:

  • 一个线程崩溃,会导致其所属进程的所有线程崩溃
进程线程
进程是资源分配单位线程是CPU调度单位
进程拥有一个完整的资源平台线程只独占指令执行流执行的必要资源,如寄存器和栈
进程具有就绪、等待和运行三种基本状态和状态间的转换关系线程具有就绪、等待和运行三种基本状态和状态间的转换关系

线程能减小并发执行时间和空间开销

  • 线程创建时间比进程短
  • 线程的终止时间比进程短
  • 同一进程内线程的切换时间比进程短
  • 由于同一进程的各线程间共享内存和文件资源,可不通过内核进行直接通信

3. 线程的三种实现方式

3.1 用户线程

用户线程是完全建立在用户空间的线程库,用户线程的创建、调度、同步和销毁全又库函数在用户空间完成,不需要内核的帮助。因此这种线程是极其低消耗和高效的。由于早期的操作系统(如早期的unix)只支持进程,不支持线程,但是的线程是由线程库实现的,我们还是以我们上面的播放软件为例:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-exM6eZTT-1617541102315)(D:\学习总结\内存管理单元\image-20210404201905943.png)]

从代码的角度,线程其实就是一段代码逻辑,上述三段代码逻辑可以看成三个“线程”。while循环就是一个最弱智的“线程库”,线程库完成了对于线程管理工作。很多 编程语言都提供了强大的线程库,可以实现线程的创建,调度,销毁等功能。对于用户线程我们需要解释以下问题

  • 线程的管理工作是由谁来完成
  • 线程切换是否需要CPU来完成,由用户态转换到内核态
  • 操作系统是否能意识到用户线程的存在
  • 这种线程的实现方式有什么优点和缺点

首先我们来看看用户线程的概念

用户线程是由应用程序通过线程库实现的,所有的线程管理工作都是由应用程序负责,包括线程的切换工作,也就是说

  • 用户线程中,线程的切换可以在用户态下即可完成,无需操作系统干预
  • 在用户看来,是有多个线程,但是在操作系统内核看来,意识不到线程的存在,所以用户线程,是从用户视角看到的线程

下面我们来看看用户线程的特征

  • 不依赖于操作系统的内核,内核不了解用户线程的存在,可用于不支持线程的多进程操作系统
  • 在用户空间实现的线程机制,每个进程有私有的线程控制块TBC,并且由线程库维护
  • 同一进程内的用户线程切换速度快,无需用户态/内核态切换,线程管理系统的开销小,效率比较高
  • 允许每个进程拥有自己的线程调度算法

用户线程的不足:

  • 线程发起系统调用而阻塞时,则整个进程等待,并发度并不高,多个线程不可在多核处理器上并行运行
  • 不支持基于线程的处理机抢占,除非当前运行线程主动放弃,它所在进程的其他线程无法抢占CPU
  • 只能按进程分配CPU时间片,多个线程进程,每个线程的时间片较少

3.2 内核线程

由内核通过系统调用实现的线程机制,由内核完成线程的创建、终止和管理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aejf20sx-1617541102316)(D:\学习总结\内存管理单元\image-20210404203544934.png)]

  • 内核级线程的管理工作由操作系统内核完成
  • 线程调度、切换等工作都有内核负责,因此内核级线程的切换必须要在内核下才能完成
  • 操作系统会为每个内核级线程建立相应的TCB(Thread Control Block,线程控制块),通过TCB对线程进行管理,内核级线程就是从操作系统内核视角看到的线程
优点缺点
当一个线程被阻塞,其他的线程还可以继续执行,并发能力强,多线程可以在多核处理器上并发执行一个用户进程会占用多个内核级线程,线程切换由操作系统内核完成,需要切换到内核态,因此管理的成本高,开销大

3.3 组合方式

3.4 轻量级进程

它是内核支持的用户线程,一个进程可有一个或多个轻量级进程,每个轻量级进程由一个单独的内核线程来支持(Solaris和Linux)

目前使用的三种主要线程库是:posix pthreads、Windows API、JAVA。pthreads作为POSIX标准的扩展,可以提供用户级和内核级的库,实现是在pthread在Linux的libc中实现。通常的libc是glibc-glibc pthreads实现称为NPTL,其源可在gitweb中获得ftp.gnu.org/gnu/glibc。

4. 多线程模型

在支持内核级线程的系统上,根据用户级线程和内核级线程的映射关系,可以化为为以下几种多线程模型

4.1. 一对一模型:

一个用户级线程映射到一个内核级线程,每个用户进程有与用户线程同数据的内核线程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MIopuqrC-1617541102317)(D:\学习总结\内存管理单元\image-20210404204351779.png)]

优点    缺点
当一个线程被阻塞后,别的线程还可以继续执行,并发能力强,多线程可以在多核处理器上并发执行    一个用户进程占用多个内核级线程,线程切换由操作系统内核完成,需要切换到内核态,因此管理的称根本较高,开销较大

4.2. 多对一模型:

多个用户级线程映射到一个内核级线程,且一个进程只被分配一个内核级线程

优点    缺点
用户级线程的切换在用户空间即可完成,不需要切换到内核态,线程的管理开销小,效率高    当一个用户级线程被阻塞,整个进程都会被阻塞,并发度不高,多个线程不可在多核处理机上并行运行

4.3. 多对多模型:

n个用户级线程映射到m个内核级线程(n >= m),每个用户进程对应m个内核级线程,这种方式克服了多对一模型并发度不高的缺点(一个阻塞全体阻塞),又克服了一对一模型中一个用户进程占用太多内核级线程,开销太大的缺点

在这里插入图片描述

用户级线程是“代码逻辑”的载体
内核级线程是“运行机会“的载体
内核级线程中可以运行任意一个有映射关系的用户级线程代码,只有两个内核级线程中正在运行的代码逻辑都呗阻塞了,这个进程才会被阻塞

5. 总结

本章分析了为什么需要线程,其主要包括,同时也介绍了线程的基本概念和分类

  • 创建进程的开销较大: 包括了数据、代码、堆、栈等
  • 进程的隔离性过强: 进程间的交互,可以通过进程间通信,但是开销过大
  • 进程内部无法支持并行:

看了一遍排在前面的答案,类似”进程是资源分配的最小单位,线程是CPU调度的最小单位“这样的回答感觉太抽象,都不太容易让人理解。

做个简单的比喻:进程=火车,线程=车厢

  • 线程在进程下行进(单纯的车厢无法运行)
  • 一个进程可以包含多个线程(一辆火车可以有多个车厢)
  • 不同进程间数据很难共享(一辆火车上的乘客很难换到另外一辆火车,比如站点换乘)
  • 同一进程下不同线程间数据很易共享(A车厢换到B车厢很容易)
  • 进程要比线程消耗更多的计算机资源(采用多列火车相比多个车厢更耗资源)
  • 进程间不会相互影响,一个线程挂掉将导致整个进程挂掉(一列火车不会影响到另外一列火车,但是如果一列火车上中间的一节车厢着火了,将影响到所有车厢)
  • 进程可以拓展到多机,进程最多适合多核(不同火车可以开在多个轨道上,同一火车的车厢不能在行进的不同的轨道上)
  • 进程使用的内存地址可以上锁,即一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。(比如火车上的洗手间)-"互斥锁"
  • 进程使用的内存地址可以限定使用量(比如火车上的餐厅,最多只允许多少人进入,如果满了需要在门口等,等有人出来了才能进去)-“信号量”
本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号