10、用户级线程:指令的切换

为什么先讲线程?因为线程切换是只有指令序列(PC指针)在切换,加上内存切换才是进程的切换。这是从简入繁的顺序 。

1、用户级线程:用户主动切换线程
进程 = 资源 + 指令执行序列
线程保留了并发的有点,避免了进程切换的代价。

指令序列在切换的时候,需要切换PCB中记录的信息,寄存器等。能不能不切换内存映射表(寄存器还是得切换的)?答案是可以的,这就是用户级线程所做的事情。将资源和指令执行分开,一个资源+多个指令执行序列。
举个例子:一个浏览器需要从网上下载数据,需要显示文字,需要解压图片,这些不同的任务实际上都需要共享数据,没必要将数据保存在不同地方,所以很适合使用多线程设计。
使用create创建线程,主动调用yield切换线程。create是制造出第一次切换时应该的样子,yield是知道切换时需要是什么样子。
10、用户级线程:指令的切换
10、用户级线程:指令的切换

2、yield函数:切换栈
yield函数遇到什么问题:指令切换时,常常会将下一条指令压栈,以便后续恢复现场。但是对于多线程而言,不能共用一个栈,因为跳到别的线程执行的时候,会污染原来的程序栈导致无法返回正确的下一条指令。、
10、用户级线程:指令的切换

怎么解决:不同线程用不同的指令栈TCB,一个TCB关联一个用户栈,TCB切换引起用户栈切换(因为TCB中的esp记录的是栈的位置)。Yield函数先保护现场,将esp放在当前TCB中,用Next进行调度,从下一个TCB中取出esp,切换栈。使用全局栈指针esp,记录当前正在使用的栈指针,切换的时候,把当前栈指针保存到TCB中,到时候从中恢复。
为什么这样解决:最关键的地方在于,yield为什么不需要指定切换完之后要执行的下一条PC指令?⭐⭐⭐⭐⭐⭐
因为栈中的下一条PC指令是在调用yield时压进去的,别的进程调用yield之后,遇到函数的 },就会自动从栈中弹出一条指令。只要我在程序的 }之前完成了栈的切换, }之后就会自动弹出之前被压进去的下一条PC指令。根据这样的设计,线程的初始化只要在线程的初始化栈中事先存进这个线程的第一条PC指令(起始地址),那么在第一次由yield切换到这个线程时,yield的 }会自动将这个新线程中弹出这个被我们存进的第一条PC指令,开始运行新的线程。

10、用户级线程:指令的切换

3、ThreadCreate():做出两个TCB、两个栈、待切换到PC存在栈中
申请栈、申请TCB、将起始地址等压入栈中、关联TCB和栈
10、用户级线程:指令的切换
10、用户级线程:指令的切换