用户级线程与内核级线程
作者:互联网
目录
线程与进程
- 进程是资源分配的基本单位,线程是调度的基本单位。
- 进程 = 资源 + 指令执行序列,如果一个进程中有多个指令执行序列(类似多个函数),可以认为这就是多个线程。即多个线程是共享进程的资源的。通过切换线程既实现了并发,又避免了进程切换时需要切换映射表的代价。映射表实际上是用来将虚拟内存映射到真实物理内存的。
- 因此线程的切换实质上就是映射表不变而改变PC指针。
- 每个线程都有自己的栈,即线程栈。
线程的价值
- 线程即多个执行序列共享一个地址空间
用户级线程
- 用户级线程本质上是不经过内核的,感觉像是用自定义的函数Yield()来模拟调度,自己控制线程的切换。即用户级线程本质上就是一系列函数集合。
- 如上每个方框中都是一个用户级线程的代码,每个线程都有一个线程控制块TCB,每个线程都有自己的函数调用栈,栈的地址就存放在线程TCB.esp中。
- 从第一个线程,即地址100开始执行,执行到函数B则把下一个地址104压入线程1的函数栈
- 然后跳转到B开始执行,执行到Yield函数开始切换线程,如图中Yield函数的定义,注意esp是函数栈顶指针寄存器,即当前函数执行结束后会接着执行esp出栈的地址。图中示意的是线程2中的Yield函数,从线程2切换到线程1需要做两个操作,第一步是将当前栈顶指针寄存器esp中的内容保存到线程2的TCB中,即TCB2.esp中。第二步是将线程1的TCB1.esp放到cpu的寄存器esp中。即用户级线程的切换本质上就是切换TCB和每个线程的栈(也在TCB中存着)。
- 注意图中线程2的Yield函数中蓝线圈出来的部分需要删除,因为不需要手动跳转到204,只要函数Yield执行完毕(到右括号),栈顶指针寄存器就会执行出栈,并从出栈元素处开始执行,此时栈顶指针寄存器中的栈顶元素就是204,因此可以直接从204开始执行。换言之,如果在Yield中jmp语句不删去,那么会先跳转到204处执行,然后将线程1的B函数执行完毕后会接着从执行函数栈顶元素处的代码,此时栈顶是204,,,于是相当于执行了两个204处的代码。
- 用户级线程不经过内核,少了进出内核的消耗,因此效率较高,但是如果某个线程要与硬件交互,比如网卡IO,则会引起对应的进程阻塞,此时cpu不会切换到其它线程去执行,而是直接切换到了另一个进程,如果此时没有其它进程,则直接导致cpu空转。因此即使通过用户级线程启动了多个任务序列,但一旦在内核中阻塞了,则启动这多个序列的并发性就没有了效果。
- 内核级线程的TCB都在内核中,因此不用自己写Yield,而是由操作系统自动调度。
内核级线程
-
内核级线程能更好利用多核处理器,多核与多CPU的区别如下,多CPU有多个缓存和MMU,多核处理器则是使用同一套缓存和MMU。内核级线程中各个线程可以执行在不同的核上,从而实现并行。并发是同时出发交替执行,并行则是同时执行。
-
内核级线程相比用户级线程的本质区别有两点,一点是内核级线程的TCB在内核中,由内核负责切换。第二点是两个用户级线程需要两个用户(函数)栈,而两个内核级线程则需要使用两套栈,即每个TCB包含两个栈,一个用户栈一个内核栈,当切换核心机线程即切换TCB时会同时切换用户栈和内核栈,不过这都是操作系统的活啦。
-
用户线程通过中断陷入内核,然后把用户栈的一些相关信息压入内核栈,内核线程通过IRET指令返回用户态,并将内核栈中的相关信息出栈。
内核级线程切换5段论
- 因为本质上我们写的程序都是应用程序,只有遇到跟硬件交互等任务时才会陷入内核,因此五段论最开始都是在用户栈开始的。
- 第一段,用户态程序调用中断,进入切换。
- 第二段,中断处理,比如启动磁盘读或时钟中断等,这会引发TCB切换,即线程切换。
- 第三段,tcb切换,从一个线程到另一个线程。
- 第四段,内核栈切换,从一个线程的内核栈,切换另一个线程的内核栈。
- 第五段,中断出口,从内核栈切换回用户栈。
用户级线程与内核级线程的对比
标签:用户,线程,切换,执行,TCB,内核 来源: https://www.cnblogs.com/chkplusplus/p/16170563.html