type
status
date
slug
summary
tags
category
icon
password
类型
标签
状态
定义:线程是进程内部的一个执行流,是程序执行的最小单位。同一进程内的多个线程共享该进程的资源(如内存、打开的文件等),因此线程间通信更加便捷。
但经常存在同一地址空间中准并行运行多个控制线程的情形,这些线程就像分类的进程。
线程的使用
迷你进程(线程)。
人们需要多线程的原因是:在许多应用中发生着多种活动。其中某些活动随着时间的推移会被阻塞。通过将这些应用程序分解为可以准并行运行的多个顺序线程(多线程),程序设计将会变得更简单。
- 多线程的需求原因
- 可以加入一种新元素:并行实体共享同一个地址空间和所有可用数据的能力。这种能力真是多进程模型(具有不同的地址空间)无法表达的。
- 由于线程比进程更轻量级,它比进程更容易创建,也跟容易关于撤销。
- 性能方面:如果存在着大量的计算和大量的I/O处理,拥有多个线程允许这些活动彼此重叠进行,从而会加快应用程序执行的速度。
在多CPU系统中,多线程使得真正的并行有了实现的可能。
假设字处理软件被编写成含有两个线程的程序。一个线程与用户交互,而另一个在后台重新进行格式处理。一旦在第1页中的语句被删除掉,交互线程就立即通知格式化线程对整本书重新进行处理。同时,交互线程继续监控键盘和鼠标,并响应诸如滚动第1页之类的简单命令,此刻,另一个线程正在后台疯狂地运算。如果有点运气的话,重新格式化会在用户请求查看第600页之前完成,这样,第600页页面就立即可以在屏幕上显示出来假设字处理软件被编写成含有两个线程的程序。一个线程与用户交互,而另一个在后台重新进行格式处理一旦在第1页中的语句被删除掉,交互线程就立即通知格式化线程对整本书重新进行处理。同时,交互线程继续监控键盘和鼠标,并响应诸如滚动第1页之类的简单命令,此刻,另一个线程正在后台疯狂地运算。如果有点运气的话,重新格式化会在用户请求查看第600页之前完成,这样,第600页页面就立即可以在屏幕上显示出来。
再增加一个线程处理磁盘备份如下:

如果程序是单线程的,则再进行磁盘备份时,来着鼠标和键盘的命令就会被忽略。
也可以让键盘和鼠标事件中断磁盘备份,但是却引入了负责的中断驱动程序设计模型。
- 多线程使得顺序进程的思想得以保留,这种顺序进程阻塞了系统调用,但是仍旧实现了并行性。对系统调用进行阻塞使程序设计变得简单,并且并行改善了性能。单线程虽然保留了阻塞系统抽象,但是却放弃了性能。

3. 多线程提供了一种处理极大量数据的思路:
有关进程利用用一个输入线程、一个处理线程和一个输出线程构造的模型。输入、处理和输出可以全部同时进行。
这种模型只有当系统调用只阻塞调用线程而不是阻塞整个进程时,才能正常工作。
线程模型
- 进程模型基于两种独立概念:资源分组处理和执行,将着两种概念分开就得到了线程的概念。
- 理解进程的一个角度:
- 用某种方法把相关的资源集中在一起。进程有存放程序正文和数据以及其他资源的地址空间。
- 进程拥有一个执行的线程,简写为线程(thread)。
在线程中有一个程序计数器,用来记录接着要执行哪一条指令。线程拥有寄存器,用来保存线程当前的工作变量。线程还拥有一个堆栈,用来记录执行历史,其中每一帧保存了一个已调用的但是还没有从中返回的过程。
- 在同一个进程环境中,允许彼此之间有较大独立性的多个线程执行。 多个线程共享同一个地址空间和其他资源。
- 在同一给进程种并行运行多个线程。
多个进程共享物理内存、磁盘、打印机和其他资源
由于线程具有进程的某些性质,所以有时被称为轻量级进程
(lightweight process)。
- 多线程这个术语,也用来描述在同一个进程中允许多个线程的情形

- 和传统进程一样(即只有一个线程的进程),线程可以处于若干种状态的任何一个:运行、阻塞、就绪或终止。
- 每个线程都有自己的堆栈,通常每个线程都会调用不同的过程,从而有一个各自不同的执行历史,也也说明了为什么每个线程都需要有自己的堆栈。

- 每个线程都有自己的堆栈,通常每个线程都会调用不同的过程,从而有一个各自不同的执行历史,也也说明了为什么每个线程都需要有自己的堆栈。

- 所有的线程都是平等的,无论有无层次关系。
在用户空间内实现线程:
- 将整个线程包放在用户空间中,内核对线程包一无所知。
- 实现阻塞系统调。
- 全部改为非阻塞的,但是需要修改操作系统。
- 如果某个调用会产生阻塞,就提前通知。
- 页面故障
- 不可能用轮转调度的方式调度进程
- 永久性运行
- 一旦发生内核陷阱进行系统调用,若原有的线程以及发生阻塞,就很难让内核进行线程的切换。
可以在不支持线程的操作系统上实现

线程在一个运行时系统的顶部运行,这个运行时系统是一个管理线程的过程的集合。
在用户空间管理线程时,每个进程需要有其专用的线程表(thread table),用来跟踪该进程中的线程。
用户级线程允许每个进程有自己定制的调度算法。
用户级线程的缺陷:
可能的解决方法:
如果某个程序调用或者跳转到了一条不在内存的指令上,就会发生页面故障,而操作系统将到磁盘上取回这个丢失的指令
如果一个线程开始运行,那么在该进程中的其他线程就不能运行,除非第一个线程自动放弃CPU。即在一个单独的进程内部,没有时钟中断,也就不可能用轮转调度的方式调度进程。
可能的解决方法:
让运行时系统请求每秒一次的时钟信号(中断),但是这样对程序也是生硬和无序的。
在内核中实现线程
不再需要运行时系统,并且每个进程中没有线程表。并且在内核中有用来记录系统中所有线程的线程表

- 当某个线程希望创建一个新线程或者撤销一个已有线程时,它进行一个系统调用,这个系统调用通过对线程表的更新完成线程的创建或撤销工作。
- 内存的线程表保存了每个线程的寄存器、状态和其他信息。现在保存在内核中。这些信息是传统内核维护的每个单线程进程信息的子集。
- 在内核中创建或者撤销的代价较大。
线程回收:当某个线程被撤销时,就把它标志为不可运行的,但是其内核数据结构没有受到影响。稍后,在必须创建一个新线程时,就重新启动某个旧线程,从而节省了一些开销。
- 内核线程不需要任何新的、非阻塞系统调用。若某个进程中的线程引起了页面故障,内核可以方便地检查该进程是否有任何其他可运行的线程。
- 内核线程的待解决问题:
- 一个多线程进程创建新的进程
- 信号
- 速度慢
混合实现
将用户级线程的优点和内核级线程的优点结合起来。
即使用内核级线程,然后将用户级线程与某些或者全部内核线程多路复用起来,通过这种方法,编程人员可以决定有多少个内核级线程和多少个用户级线程彼此多路复通。灵活度极佳。

这种方法的内核只识别内核级线程,并对其进行调度。其中一些内核级线程会被多个用户级线程多路复用。如同在没有多线程能力操作系统中某个程中的用户级线程一样,可以创建、撤销和调度这些用户级线程。在这种模型中,每个内核级线程有一个可以轮流使用的用户级线程集合。
- Author:Uonlra
- URL:https://www.uonlra.blog//article/1ac54775-fb6a-80ed-b077-c67a9691fd23
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!