用户级线程和内核级线程(哈工大李志军)

注:本文图片引用自慕课的PPT
b站:https://www.bilibili.com/video/BV1d4411v7u7

用户级线程

一个浏览器的模型:

在这里插入图片描述

两个执行序列与一个栈的弊端:

在这里插入图片描述
Yield()是一个切换函数,在线程切换中,我们需要像Yield()这样的函数允许B->C->D并直接返回 ->B,否则只能逐层调用返回,这不是线程切换想要的结果。

这种情况如果我们希望用Yield()D返回到B,即直接跳转到204,但当函数返回时(ret指令),我们发现此时栈已经乱了,ret将会导致意外,会使程序跳转到404.
在这里插入图片描述

从一个栈到两个栈

在这里插入图片描述
如果使用两个栈,那么我们自然需要在Yield()中切换栈,把栈顶指针存入到该线程的TCB(线程控制块)中。

当程序在D中,调用Yield()当前栈2顶部压入404,调用Yield()时,交换栈,此时Yield()函数返回时弹出的栈是栈1,而此时栈1顶部为204正好与我们跳转到204的目的相同,因此Yield()不需要jmp 204

两个线程:两个TCB+两个栈+切换的PC在栈中

在这里插入图片描述

用户级线程的弊端

在这里插入图片描述

当用户级线程调用内核时,进入内核态之后,若内核进程需要等待网卡IO,需要较长时间而导致进程阻塞,用户态的多线程将没有任何作用。

核心级线程

在这里插入图片描述
在这里插入图片描述
用户线程是Yield(),内核线程切换Schedule()Schedule()调度是由系统决定,具有强制性,Yield()用户可主动释放。
如果实现了核心级线程,则有效解决了仅用户级线程的缺陷。

切换进程与切换线程:

  • 进程需要分配资源,所以只有内核级的进程。
  • 切换进程:切换指令流 + 切换资源
  • 切换内核级线程即为切换指令流,是切换进程中的一部分。

在这里插入图片描述
多处理器与多核的区别,多处理器每个运算器都有自己的缓存和内存映射,多核心处理器共用一个。
多核处理器要想有作用,必须支持核心级线程。
在多核处理器中, 因为多个线程共用一个资源,多核被分配到多个线程,而只需一套MMU(内存管理单元)。

从一个栈到一套栈

每个用户级线程即需要一个栈,而实现用户级线程需要一套栈即两个栈:用户栈 + 内核栈
在这里插入图片描述

用户栈到内核栈的关联:

在这里插入图片描述
SS:SP为用户栈指针,CS:PC(IP)记录用户程序的位置。
在这里插入图片描述
在这里插入图片描述
esp 被赋值 为TCB1中的值,执行sys_read()而阻塞,内核线程调度使用switch_to()并切换栈
cur是当前线程的TCB,next是下一个线程的TCB。
PC:CS 为返回用户态的地址,SS:SP指向用户态栈。
要让以上PC,CS,SS,SP都弹出栈,那么? ? ? ? 的指令应为iret (中断返回)
在这里插入图片描述

小结:内核线程switch_to的五段论

在这里插入图片描述

  1. 准备中断:为整个处理链条做准备,中断进入内核态
  2. 中断处理:当引发阻塞(IO 或时钟中断)时
  3. 引发切换,并找到下一个TCBnext =...
  4. 内核栈切换:交换指针完成栈交换后,执行 ret 指令。
  5. 中断出口:交换后将弹出当前栈顶即上文图中的 ? ? ? ?的命令,在上文已经解释到, ? ? ? ?iret(中断返回),使 CS,PC,SS,SP等弹出栈,恢复到用户态。
  6. (附加)因为进程切换,还要切换地址映射表,到内存管理部分时再研究。

ThreadCreate 实现模型

在这里插入图片描述

  1. 申请内存:get_free_page()作为TCB
  2. 内核栈初始化
  3. 传入用户栈
  4. 并将两个栈通过指针连接起来,将内核函数地址(图中为500)和 CS (0F)压入栈,并压入参数。
  5. 设置TCB指向内核栈
  6. TCB就绪,入队。

用户级线程和核心级线程的对比

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章