线程、对称多处理(SMP)和微内核

线程概念

线程也称为轻量级进程(lightweight process),是程序的一个片段的执行。线程的组成为:线程ID、当前的指针、少量寄存器、堆栈(stack)。线程是CPU调度和分配的基本单位,线程自己不拥有资源,但是线程有自己的堆栈(用于函数实参和内部分配变量存储)。同一个进程下的线程共享进程的资源(包括I/O设备、文件描述符fd、堆、进程的代码段等)。每个进程至少有一个线程,如果进程只有一个线程,那么这个线程就是程序本身。线程间也可以并发执行。线程也拥有三个基本状态:就绪状态、阻塞状态、运行状态。

多线程

多线程是指操作系统在单个进程内支持多个并发执行路径的命令。

Single-threaded approach refers to the traditional approach of a single thread of execution per process, in which the concept of a thread is not recognized(单线程指一个进程中只有一个线程在执行的传统方法(还没有明确线程的概念))

在多线程环境中,进程被定义成资源分配的一个单位和一个保护的单位,与进程相关联的的有:

  • 存放进程映像的虚拟地址空间
  • 受保护地对处理器,其他进程,文件和I/0资源的访问
  • 传统进程原先所承担的控制流执行任务交给称作线程的部分完成

​ 进程和线程

image.png

一个进程中,可能有一个或多个线程,每个线程有:

  • 线程执行状态(运行、就绪、等待、…);
  • 当线程不运行时,有一个受保护的线程上下文,用于存储现场信息。所以,观察线程的一种方式是运行在进程内一个独立的程序计数器;
  • 一个执行堆栈
  • 一个容纳局部变量的主存存储区。

​ 单线程和多线程的进程模型

image.png

线程的重要优点如下:

  1. 在一个已有进程中创建一个新线程比创建一个全新进程所需的时间要少许多。Mach开发者的研究表明,线程创建要比在UNX中的进程创建快10倍。

  2. 终止一个线程比终止一个进程花费的时间少。

  3. 同一进程内线程间切换比进程间切换花费的时间少。

  4. 线程提高了不同的执行程序间通信的效率。在大多数操作系统中,独立进程间的通信需要内核的介人,以提供保护和通信所需要的机制。但是,由于在同一个进程中的线程共享内存和文件,它们无需调用内核就可以互相通信。


线程功能特性

线程状态

​ 1. 4种与线程状态改变相关的基本操作

  • 派生
  • 阻塞
  • 解除阻塞
  • 结束
image.png

上述两幅图显示了一个执行了两个远程过程调用(rpc)的程序这两个调用分别涉及两个不同的主机,用于获得一个组合效果。

单线程程序中,其结果是按顺序获得的,每个程序必须依次等待来自每个服务器的响应。

若重写这个程序,为每个RPC使用一个独立的线程,可以是速度得到实质的提高。

  1. 线程同步

    一个进程中的所有线程共享同一个地址空间和诸如打开的文件之类的其他资源。一个线程对资源的任何修改都会影响同一个进程中其他线程的环境。因此,需要同步各种线程的活动,以便它们互不干涉且不破坏数据结构。例如,如果两个线程都试图同时往一个双向链表中增加一个元素,则可能会丢失一个元素或者破坏链表结构

    image.png


用户级和内核级线程

线程的实现可以分为两大类:用户级线程(ULT)和内核级线程(KLT)

用户级线程

  • Multithread implemented by a threads library(线程的机制由线程库实现)
  • All thread management is done by the application(线程由应用程序管理)
  • The kernel is not aware of the existence of threads & scheduling is done on a process basis(内核透明,调度基于进程)

BiEbl9.png

使用用户级线程而不是内核级线程有很多优点,包括:

1)由于所有线程管理数据结构都在一个进程的用户地址空间中,线程切换不需要内核态特权,因此,进程不需要为了线程管理而切换到内核态,这节省了两次状态转换(从用户态到内核态;从内核态返回到用户态)的开销。

2)调度可以是应用程序相关的。一个应用程序可能更适合简单的轮转调度算法,而另一个应用程序可能更适合基于优先级的调度算法。可以做到为应用程序量身定做调度算法而不扰乱底层的操作系统调度程序。

3)用户级线程可以在任何操作系统中运行,不需要对底层内核进行修改以支持用户级线程。线程库是一组供所有应用程序共享的应用程序级别的函数。

缺点:

  • One thread is blocked, all other threads of the process are blocked
  • A multithreaded application cannot take advantage of multiprocessing(不能有效的利用多处理器的优势)
    • Ways to work around these drawbacks:(解决办法)
      Multiple processes(多线程变成多进程 )
      Jacketing(把阻塞式系统调用改造成非阻塞式的)

内核级线程

  • Kernel maintains context information for the process and the threads(内核维护进程和线程的上下文信息)
  • Scheduling is done on a thread basis(调度是以线程为基础)

BiZCNT.png

用内核级线程而不用用户级线程的好处

  • Multiple threads in one process can simultaneously run on multiple processors(线程能同时在多处理器上运行)
  • One threads blocked cannot make the other threads within the same process blocked(一个线程阻塞不会引起在同一进程里的线程阻塞)
  • Kernel routines themselves can be multithreaded(内核本身就可以多线程,提高效率)

用内核级线程的坏处

The principal disadvantage is that thread switch requires mode switches(模式切换) to the kernel(内核切换的效率)

BiZ2V0.png

组合方法

  1. Thread creation done in the user space(在用户空间创建线程)
  2. The multiple ULTs from a single application are mapped onto some (smaller or equal) number of
  3. KLTs(用户级线程映射到内核级,一般内核级数量小于或等于用户级线程)
  4. Bulk of scheduling and synchronization of threads within application(应用程序中的线程分组进行调度和同步)

Bims7q.png

对称多处理

SMP体系结构

SMP:一种通过复用处理器提高程序执行并行性的方式。

根据SMP,计算机系统可以分为以下四类:

  • 单指令单数据流(SISD):一个单处理器执行一个单指令流,对保存在一个存储器中的数据进程进行操作。
  • 单指令多数据流(SIMD):一个机器指令控制多个处理部件步伐一致的同时执行。每个处理部件都有一个相关的数据处理空间,因此,每条指令由不同的处理器在不同   的数据集合上执行。
  • 多指令单数据流(MISD):一系列数据被传送到一组处理器上,每个处理器执行不同的指令序列。
  • **多指令多数据流(MIMD)**:一组处理器同时在不同的数据集上执行不同的指令序列

在MIMD结构中,处理器是通用的,它们必须能够处理执行相应的数据转换所需的所有指令。

  MIMD可以根据处理器的通信进一步细化。如果每个处理器都有一个专用的存储器,则每个处理部件都是一个独立的计算机。计算机间的通信或者借助于固定的路径,或者借助于某些网络设施,这类系统称为集群系统。如果处理器共享一个公用的存储器,每个处理器都访问保存在共享存储器中的程序和数据,处理器之间通过这个存储器相互通信,则这类系统称为共享存储器多处理机系统。

  共享存储器多处理机系统的一个常用分类标准是基于”如何把进程分配给处理器“。最基本的两种手段是主/从结构对称结构

  在主/从结构中,操作系统的内核总是运行在某个特定的处理器上,其他处理器用于执行用户程序和操作系统的使用程序。主处理器负责调度进程或线程,如果一个处于运行的进程或线程需要使用系统的服务(如一次I/O调用),则它必须给主处理器发送请求,并等待服务的处理。这种方式非常简单,一个处理器控制了所有存储器和I/O资源,因此可以简化冲突的解决方案。但是这种方式也有明显的缺点:

  1. 主处理器的失败将导致整个系统的失败;

  2. 由于主处理器必须负责所有的进程调度和管理,因此可能成为性能瓶颈;

  在对称多处理系统中,内核可以在任何处理器上执行,并且每个处理器可以从可用的进程或线程池中进行各自的调度工作。内核也可以由多进程或多线程构成,允许部分内核并行执行。SMP方法增加了操作系统的复杂性,它必须确保两个处理器不会选择同一个进程,并且要确保队列不会丢失,因此需要解决同步的问题。

  img

SMP系统的组织结构

  SMP系统中有多个处理器,每一个都含有它自己的控制单元,算术逻辑单元和寄存器;每个处理器都可以通过某种互联机制访问一个共享的主存和I/O设备,通常是系统总线。处理器之间还可以通过存储器中的共享地址空间中的消息和状态信息相互通信。存储器通常被组织为可以允许同时有多个对存储器不同独立部分的访问。现代计算机中,处理器通常有一级专用的高速缓存,由于每个高速缓存含有主存中的一部分映像,如果某个处理器修改了其中的一个字,那么其他高速缓存中的这个字将变得无效,这就带来了高速缓存的一致性问题,这个问题的解决通常是通过硬件的方式。

  Bmfkmd.png

多处理器操作系统的设计

  并发进程或线程:为了允许多个处理器同时执行相同的内核代码,内核例程必须是可重入的。多处理器执行内核的相同部分和不同部分时,必须正确的管理内核表和管理结构,以避免死锁或非法操作;

  调度:调度可以由任何处理器执行,因此必须避免冲突。如果使用内核级多线程,则可能出现同一时刻,多个处理器同时从同一个进程中调度多个线程的情况;

  同步:因此存在多个进程都可能访问共享地址空间和共享I/O资源的情况,因此需要提供同步机制。同步是指实施互斥和事件排序的机制。锁是一个通用的同步机制;

  存储器管理:多处理器系统为了提高性能,尽可能利用硬件的并行性,如多端口存储器,还必须协调不同处理器上的分页机制,以确保多个处理器共享页或段时页面的一致性问题,以及页替换策略;

  可靠性和容错:当一个处理器处理失败时,操作系统应该提供功能衰减能力,重新组织管理表


微内核

传统的分层操作系统:

  操作系统按功能分层,只有相邻两层之间可以发生交互。在分层结构中,大多数层或所有层都在内核模式下运行。分层结构的主要问题在于,每一层必须处理相当多的功能,某一层的变化可能对相邻层产生巨大的影响,并且这些影响跟踪起来非常困难。因此导致的问题是:操作系统很难通过增加一层或者减小一层来实现专有的版本,而且相邻层之间交互太多,难以保证安全性。

微内核操作系统

  微内核的基本原理是:只有最基本的操作系统功能才放入内核中。非基本的服务和应用程序在内核之上构建,并在用户模式下运行。关于什么功能应该放入微内核,不同的设计有不同的方式,但是共同特点是许多传统上属于操作系统一部分的功能现在都是外部子系统,包括设备驱动程序文件系统虚存管理程序窗口系统安全服务,它们可以和内核交互,也可以相互交互。

  微内核结构使用一个水平分层代替传统的纵向分层,所有微内核之外的操作系统构件都被当作服务进程来实现,它们可以通过微内核传递消息来实现相互之间的交互。因此,微内核还可以验证消息并授权访问硬件,而且微内核还执行保护功能,阻止非法的信息等。

  例如,应用程序如果要打开一个文件,则它发送消息给文件系统服务,如果他想创建一个进程或线程,则它发送消息给进程服务进程。每个服务进程之间可以相互通信,并可以调用微内核中的功能。

  img

微内核的优点:

  提供一致的接口:微内核设计为进程请求提供一致的接口,进程不在需要区分内核级服务还是用户级服务,因为都是通过消息传递;

  可扩展性:使用微内核结构,当需要为系统增加新的服务时,只是增加一个新的服务进程,而不是修改内核;

  灵活性:可以根据需要定制不同的服务进程,例如分布式系统需要增加安全性相关的服务;

  可移植性:在微内核结构中,大部分处理器专用代码都在微内核中,如果需要移植到另一个处理器上时,需要修改的代码很少;

  可靠性:模块化的结构有利于增加稳定性,而且足够小的微内核更能进行充分的测试,为外部的系统服务提供更稳定的代码。而且它只提供少量的API和交互方式给程序员,可以减少组件之间的相互影响;

  分布式系统的支持:如果一个客户往一个服务进程发送消息时,该消息包含请求服务的标识符。在分布式系统被配置为所有进程和服务都具有唯一的标识符,那么实际上在微内核级别上有一个单独的系统映像,进程可以在不知道目标服务驻留在哪台机器上的情况下发送信息;

  适用于面向对象设计:微内核设计和操作系统模块化的开发都可以借助面向对象的原理。例如,一种方式是构造组件,组件间通过组建接口交互,它们可以通过搭积木的方式构件软件;

微内核的性能:

  通过微内核构造和发送消息,比直接进行一次系统调用发花费更多时间。一种解决方式是将一些关键服务和驱动程序重新放回内核中,可以减少用户-内核模式以及进程间的切换次数,但是这是以牺牲微内核的设计强度为代价;另一种解决方式是通过正确的设计,构造一个非常小的内核,可以消除消除性能损失并提高灵活性。

微内核设计

  低级存储器管理:微内核必须控制硬件上的地址空间,使得操作系统可以在进程级进行保护。微内核只负责把每个虚页映射到一个物理页帧,而存储管理部分则在内核外实现,包括保护一个进程的地址空间不被其他进程干涉,页面替换算法以及分页逻辑。例如,内核外的虚拟存储器负责何时把一个页面调入存储器或者何时换出一个页面,而内核就负责将这些页面索引映射到物理地址。

  当一个应用程序发生引用了不在主存中的一页的时候,,内核发生缺页错误并执行陷阱,内核给页面管理器所在进程发送一条消息。页面管理器决定装载页面并分配一个页帧,页面管理器和内核进行交互,以把页面管理器的逻辑操作映射到物理存储器。一旦该页可用,页面管理器就给应用程序发送一条中断恢复的消息。

  img

  这种技术可以不用调用内核操作,就将文件和数据库映射到用户地址空间。微内核一共提供了三个内核操作用于支持核外的分页和虚存管理:

    授权:一个地址空间的所有者可以授权其他进程使用它的某些页。内核把这些页从授权者的地址空间移出,并把它们分配给指定的进程;

    映射:一个进程可以把它的任何页映射到另一个进程的地址空间,使得两个进程都可以访问这些页,就形成了共享内存。内核把这些页面分配给最初的所有者,为其他进程提供一个映射以便访问它们;

    刷新:进程可以回收授权给其他进程或者映射到另外进程的任何页面;

  进程间的通信:微内核操作系统中,进程之间或者线程之间进行通信的基本方式是消息。消息包括消息头和消息体:消息头描述了发送和接受消息的进程;消息体包含数据或者指向数据的指针。

  可以认为进程间通信是基于与进程相关联的端口(某个进程的消息序列),端口可以表明那些进程可以与这个进程通信。端口的标识和功能由内核维护,进程可以给内核发送一条指明新端口功能的消息,进程可以允许对自身授权新的访问。

  地址空间不重叠的进程间的消息传递涉及到存储器到存储器的复制,因此受限于存储器的速度,复制的速度会远远低于处理器的速度。

  I/O和中断管理:在为内核结构中,硬件中断可能被当作消息处理。微内核可以识别中断但是不处理中断,它会产生一条消息给与该中断相关联的用户级线程。因此,当允许一个中断时,一个特定的用户级进程被指派给这个中断,并由内核维护这个映射。把中断转换为消息的工作必须由微内核完成,但是微内核并不涉及设备专用的中断处理。

  把硬件看做一组具有唯一标识号的线程,并给用户空间中相关的软件线程发送消息,接受线程确定消息是否来自一个中断,并确定具体是哪个中断。

  img