此篇文章解释交替进程步骤中的切换。
又因为进程的切换=线程切换+映射表的切换(与内存管理有关),线程切换有用户级线程切换和内核级线程切换,而进程是要深入内核的,所以此处是内核级切换。
所可以从内核级线程切换来理解进程切换。
而用户级切换是内核级切换的基础。
用户级线程
-
一个切换例子:
关键:两个TCB+两个栈
Yield()就是切换esp,也就是栈顶指针,即切换了栈
Yield()之后通过栈的弹出继续另一个线程的执行 -
线程的创建:
步骤:
1、申请内存作为TCB
2、申请内存作为栈
3、在栈里面压入起始地址
核心级线程
-
为什么有核心级线程?
1、用户级线程内核的切换由用户态程序自己控制内核切换,不需要内核干涉,少了进出内核态的消耗,但不能很好的利用多核Cpu。操作系统内核不知道多线程的存在,因此一个线程阻塞将使得整个进程(包括它的所有线程)阻塞。
2、内核级线程切换由内核控制,当线程进行切换的时候,由用户态转化为内核态。一个内核线程由于I/O操作而阻塞,不会影响其它线程的运行,具有更好的并发性,能更好的利用多核cpu。
3、关系:用户级线程是核心级线程的基础。schedule()是核心级的yield(),是用户接触不到的。
4、区别:一个TCB关联一套栈。TCB切换一套栈,用户栈和核心栈都要切换。 -
内核级线程的结构:
1、对于栈顶的段地址,其是存放在段寄存器 SS 中的,而对于栈顶的偏移地址,其则是存放在 SP 寄存器中的 。在任何时刻,SS:SP 都是指向栈顶元素 。ss,sp将内核栈与用户栈相连,
2、CS,code segment,存放段基址的寄存器 -
如何从用户到内核:中断
举个例子:
-
内核级线程的切换:
ret切到内核程序的意思是改变esp之后通过ret弹栈,获得下一个线程的执行地址。
在????处,是包含iret(中断服务程序的最后一条指令)的代码,能够弹栈、从内核态回到用户态。
总结下来,内核级切换步骤如下图(五段式):
用户栈->内核栈->TCB->schedule()切换到下一个进程的TCB->内核栈->用户栈
- 线程的创建thread create
1、为TCB申请内存
2、为内核栈申请内存
3、内核栈初始化(把内核栈和用户栈关联、tcb关联内核栈……)
用户级线程 vs 核心级线程
用户级线程想开多少都行,但是核心级不行,因为提供开的内核资源有限。用户级线程可以改调度方式yield(),但是核心级线程内是无法修改的。