今天从一颗
开始,我们看看如何从小树苗长成一颗苍天大树。
CPU运转起来很简单,就是不断的从内存取值执行。
IO是个耗费时间的活,如果CPU在取值执行过程中,遇到了IO指令,那么必须等当前IO执行完毕后,才能继续取出下一条指令去执行,显然这种同步等待机制,并没有充分利用CPU的性能。
如何解决上面同步等待的问题呢?
程序间交替执行,意味着程序间需要来回跳转执行,既然需要跳转,就需要保护现场和恢复现场,那么对应的就需要用栈来完成这两个任务。
既然需要用栈来保存现场和恢复现场,那么处于节约内存考虑,一个栈够吗?
显然不行,大家自己推一遍过程就知道了,那既然不行,该怎么办呢?
既然一个栈,那就两个栈,既然有了两个栈,随之就引出了一个问题,在两个栈切换时,如何知道当前栈的栈顶位置呢?
例如: esp栈顶指针寄存器一开始指向线程1的栈顶,但是此时要切换到线程2,那么就需要把esp指针移动到线程2的栈顶位置,那么线程2的栈顶位置搁哪保存呢?
为了方便切换时,找到对应线程的栈顶位置,因此由了TCB的诞生,TCB中保存当前线程栈顶位置和其他一些信息,因此如果要进行线程切换,首先需要通过下一个TCB,再通过TCB找到新的栈顶位置,然后将esp指针指向新栈顶位置。
因为用户级线程的切换都是在用户态完成的,内核态是不知道当前进程中有多少个用户级线程的,那么一但进程1中某个用户级线程进入内核态后,产生了阻塞,那么此时是无法切换到进程1中其他用户级线程继续执行的,而是会直接切换到进程2继续执行。
既然用户级线程在用户态完成的线程切换,内核态看不见,不知道。
那么对应就有了在内核态完成切换的线程,即内核级线程。
因为通过中断进入内核态,再通过中断返回时,也是需要回到进入中断前用户态的状态的,那么就需要在内核态中设置一个栈,来保存中断进入时,用户态的状态,该栈就被叫做内核栈。
当然,因为内核态中会去进行系统调用,也需要调用函数,那么也会有保护现场和恢复现场的需要,因此肯定也是需要一个栈的。
有人问,为什么不直接使用用户栈来保存相关记录呢? 而非要在内核态再创建一个内核栈,不是浪费内存吗?
随之就引入了内核栈,每个内核级线程对应一个用户栈,一个内核栈,并且因为切换是通过内核栈完成的,因此TCB中保存的是内核栈的栈顶位置。
如果在屏幕上交替打印出A和B呢?
如果要写出交替打印A和B的程序,不就是创建两个进程,一个不断打印A,另一个不断打印B吗?
如果把上面c语言,翻译成汇编形式,就是下面这样:
首先一上来先通过fork来创建一个进程,fork函数通过int 0x80号中断进入内核,下面看看他干了啥?
int 0x80要进入内核态,中断过程中会将用户栈状态和当前标志寄存器,EIP,CS等都压入内核栈保存。
int 0x80会去进行系统调用,首先通过中断类型号0x80加上系统调用号,最终定位到sys_fork函数。
sys_fork最终会跳转到copy_process处执行。
copy_process主要做的工作就是初始化PCB和当前进程对应的TSS,而新创建进程的用户态状态基本都copy父进程
包括一会该子进程开始执行的时候,也是直接从父进程进入中断时,压入栈中的EIP处开始执行,并且将eax设置为了0,这样就可以确保子进程去执行自己的代码,而不会与父进程执行相同的指令序列。
父进程执行完sys_fork后返回,返回后需要判断是否进入阻塞,时间片是否到期,然后这里假设这里父进程不满足切换条件,然后返回到用户态,继续去创建进程B。
进程B的创建和进程A一样,只不过此时进程A和进程B形成了一个进程就绪队列
父进程创建完进程A和进程B后,进入等待状态。
wait函数,也会进行系统调用,底层会将自己的状态设置为阻塞态,然后进行进程调度。
假设此时调度算法,默认选中就绪队列中第一个元素,即切换到进程A执行。
switch_to简而言之就是先将当前CPU状态拍到父进程的TSS中,然后再将进程A中的TSS状态信息拍到CPU上。
因为进程A的TSS中设置的初始EIP=100,并且eax等于0,因此当开始执行进程A时,首先判断eax是否为0,如果为0,则满足条件,跳转到208处执行,即不断打印A。
上面,我们完成了进程A的执行,进程A会不断在屏幕上打印A,那么我们的期望是A和B不断交替打印,那就需要让B进程也执行起来,然后A进程和B进程交替执行
加入时钟中断,每产生一次时钟中断,就把当前进程的counter–,当某次时钟中断发生时,当前进程–counter=0,说明当前进程的时间片用完了,需要进行切换。
当进程A的时间片用完后,需要切换到进程B继续执行。
通过switch_to将当前CPU状态扣到进程A的TSS上面,然后将进程B的TSS拍到CPU上面,就完成了进程的切换。
接下来,进程B开始执行,然后不断去打印B
交替的打出A和B…
已经打出了B,完事了吗? 何为交替? 接下来会发生什么?把自己变成计算机想一想…
中断,仍然是中断…什么中断?
然后,当进程B打印了一会B后,有因为进程B的时间片到期,切换到进程A继续执行。
而接下来,就会重复因为时间片到期,进程间不断切换,从而完成A和B交替打印的结果
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://cjdhy.blog.csdn.net/article/details/125740117
内容来源于网络,如有侵权,请联系作者删除!