进程,线程,协程(用户级线程)相关知识

一、进程,线程,协程(用户级线程)

1、进程

为了方便管理计算机的多道程序,计算机操作系统引入进程概念

进程是系统进行资源分配和调度的基本单位

进程作为程序独立运行的载体保障程序的独立运行

进程的存在使操作系统的资源利用率大幅度提升

进程的控制结构是进程控制块,简称PCB,PCB是进程存在的唯一标识,这意味一个进程一定会有对应的PCB,进程消失,PCB也会随之消失,PCB主要包含以下四类信息:

1、进程描述信息

  • 进程唯一的标记符,类似唯一id
  • 用户标识符,进程归属的用户,用户标识符主要为共享和保护服务

2、进程控制和管理信息

  • 进程当前状态,比如运行、就绪、阻塞等,作为处理机分配调度的依据
  • 进程优先级,描述进程抢占处理机的优先级,优先级高的进程可以优先获得处理机

3、资源分配清单

  • 用于说明有关内存地址空间或虚拟地址空间的状况,所打开文件的列表和所使用的输入/输出设备信息

4、CPU 相关信息

  • 指 CPU中各寄存器值,当进程被切换时,CPU状态信息都必须保存在相应的PCB中,以便进程重新执行时,能再从断点继续执行。

2、线程

为了提高系统内程序的并发程度,减少并发开销,计算机操作系统引入线程概念

线程是运行调度的最小单位

线程从属于进程,是进程实际运行工作的单位

一个进程可以有多个线程,当进程只有一个线程时,可以认为进程等于线程,每个线程可以执行不同的任务,线程比进程更轻量

线程本身不拥有资源,它们共享进程的资源,因此会产生资源竞争,需要通过锁机制来协同

当进程中的一个线程奔溃时,会导致其所属进程的所有线程奔溃(一般游戏的用户设计不会采用多线程方式)

线程的控制结构是线程控制块,简称TCB,TCB是线程存在的唯一标识,这意味一个线程一定会有对应的TCB,线程消失,TCB也会随之消失,TCB主要包含以下信息:

  • 线程标识符,为每个线程赋予一个唯一的线程标识符

  • 一组寄存器,包括程序计数器PC、状态寄存器和通用寄存器的内容

  • 线程运行状态,用于描述线程正处于何种运行状态

  • 优先级,描述线程执行的优先程度

  • 线程专有存储区,用于线程切换时存放现场保护信息,和与该线程相关的统计信息等

  • 信号屏蔽,即对某些信号加以屏蔽

  • 堆栈指针,在线程运行时,经常会进行过程调用,而过程的调用通常会出现多重嵌套的情况,这样,就必须将每次过程调用中所使用的局部变量以及返回地址保存起来。为此,应为每个线程设置一个堆栈,用它来保存局部变量和返回地址。相应地,在TCB中,也须设置两个指向堆栈的指针:指向用户自已堆栈的指针和指向核心栈的指针。前者是指当线程运行在用户态时,使用用户自己的用户栈来保存局部变量和返回地址,后者是指当线程运行在核心态时使用系统的核心栈。

3、协程(用户级线程)

一个线程能对应多个协程

系统无法感知协程,因此不能被系统调度,也不能发挥多核优势,但因为不消耗内核资源,所以可以大量创建,协程由用户自行调度

协程调度一直处于用户态,因此上下文切换成本非常低

协程拥有自己的TCB,包括寄存器上下文和栈

二、进程,线程,协程之间的不同

1、进程,线程之间的不同

进程是最小的资源(包括内存、打开的文件等)分配单位,线程是最小的运行单位

进程拥有一个完整的资源平台,而线程只独享必不可少的资源,如寄存器和栈

线程同样具有就绪、阻塞、执行三种基本状态,同样具有状态之间的转换关系(和进程大同小异)

线程的创建、终止时间比进程快,因为进程在创建的过程中,还需要资源管理信息,比如内存管理信息、文件管理信息,所以线程在创建的过程中,不会涉及这些资源管理信息,而是共享它们(线程管理的资源较少)

同一个进程内的线程切换比进程切换快,因为线程具有相同的地址空间(虚拟内存共享),这意味着同一个进程的线程都具有同一个页表,那么在切换的时候不需要切换页表。而对于进程之间的切换,切换的时候要把页表给切换掉,而页表的切换过程开销是比较大的

由于同一进程的各线程间共享内存和文件资源,那么在线程之间数据传递的时候,就不需要经过内核了,这就使得线程之间的数据交互效率更高了

每个进程都有独立的地址空间,一个进程崩溃不影响其它进程;一个进程中的多个线程共享该进程的地址空间,一个线程的非法操作会使整个进程崩溃

2、线程,协程之间的不同(主要是受内核调度和不受内核调度的不同)

线程是运行调度的最小单位,由系统自主调度;协程由用户调度,系统无法感知

线程运行状态切换及上下文切换因为需要内核调度,所以会有用户态-内核态-用户态的转变,会消耗系统资源,时间代价较大;而协程完全由程序控制,状态切换及上下文切换不需要内核参与,代价很小

线程进程都是同步机制,而协程则是异步。

协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态

线程是抢占式,而协程是非抢占式的,所以需要用户自己释放使用权来切换到其他协程,因此同一时间其实只有一个协程拥有运行权,相当于单线程的能力

协程并不是取代线程, 而且抽象于线程之上, 线程是被分割的CPU资源, 协程是组织好的代码流程, 协程需要线程来承载运行, 线程是协程的资源, 但协程不会直接使用线程, 协程直接利用的是执行器(Interceptor), 执行器可以关联任意线程或线程池, 可以使当前线程, UI线程, 或新建新程.

不需要多线程的锁机制:因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多

三、用户态和内核态

1、用户态

用户空间:存放对是用户程序的代码和数据

进程在执行用户自己的代码(非系统调用类函数)

CPU只可以访问有限的内存,不允许访问外围设备

2、内核态

内核空间:存放内核代码和数据

进程执行操作系统内核的代码

CPU可以访问内存所有数据和外围设备

3、用户态、内核态切换过程中进程的变化

进程进入内核态后,先把用户态堆栈的地址保存在内核栈之中,然后设置堆栈指针寄存器的内容为内核栈的地址,这样就完成了用户栈向内核栈的转换;当进程从内核态恢复到用户态时,在内核态执行的最后将保存在内核栈里面的用户栈的地址恢复到堆栈指针寄存器即可。这样就实现了内核栈和用户栈的互转。

在进程从用户态转到内核态的时候,进程的内核栈总是空的。这是因为,当进程在用户态运行时,使用的是用户栈,当进程陷入到内核态时,内核栈保存进程在内核态运行的相关信息,但是一旦进程返回到用户态后,内核栈中保存的信息无效,会全部恢复,因此每次进程从用户态陷入内核的时候得到的内核栈都是空的。所以在进程陷入内核的时候,直接把内核栈的栈底地址给堆栈指针寄存器就可以了。

4、用户态切换内核态的时机

  • 系统调用

这是用户态进程主动要求切换到内核态的一种方式,用户态进程通过系统调用申请使用操作系统提供的服务程序完成工作,比如前例中fork()实际上就是执行了一个创建新进程的系统调用。而系统调用的机制其核心还是使用了操作系统为用户特别开放的一个中断来实现,例如Linux的int 80h中断。

  • 异常

当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。

  • 外围设备的中断

当外围设备完成用户请求的操作后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。

这3种方式是系统在运行时由用户态转到内核态的最主要方式,其中系统调用可以认为是用户进程主动发起的,异常和外围设备中断则是被动的。

四、上下文切换

1、进程上下文切换

  1. 准备就绪进程运行数据
  2. CPU状态字段由用户态改为内核态(即更改权限等级3->0)
  3. 进程数据由用户栈转到内核态栈,保存当前进程运行状态到PCB
  4. 迁出当前进程数据
  5. 迁入就绪进程数据
  6. 进程数据由内核栈转到用户栈,从PCB恢复就绪上次运行状态
  7. CPU状态字段由内核态改为用户态(即更改权限等级0->3)

此过程由系统调用,所以有用户态-内核态-用户态的转换,需要对整体资源腾挪,消耗比较大。

2、(同一进程中)线程上下文切换

和进程切换基本相同,此过程同样由系统调用完成,也有用户态-内核态-用户态的转换,但是前后所需资源没有改变,只需要切换线程的私有数据、寄存器等不共享的数据,消耗较小。

3、协程上下文切换(让步)

和线程切换基本相同,但是由于没有经过系统调用,所有操作均在用户态完成,所以虽然此过程仍有寄存器和栈等信息的腾挪,但相比起来消耗非常小。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值