多线程,会减少内核态,用户态的切换,从而提高性能。
为什么要有线程,大概是这样的?
因为一个进程,要进行多个指令,如果访问地址,需要有地址,要回到映射表中。
执行不下去了,进程要切换,那么一个执行指令序列,要切换到另外一个执行指令序列,
比如A函数 从b函数执行, 那么我们只切换指令,不切换映射表,那么就是线程了。
所以,期望是操作系统减少切换映射表,避免了进程切换的代价(切换映射表比较消耗资源)
大概,面试打到这里,很浅可能也够了。
但是求知的角度,一定要好好学习一下。
(tips:进程切换其实是一样的。只不过从pcb变成了tcb)
什么是线程:
一个执行指令序列,切换到另外一个指令序列,只切指令。
映射表对应的是资源,也就是内存。
我们期望,资源和指令分开,资源不变,内存不用跟着切,多个指令多个程序交替进行,切起来还快。
并发的特点,还保证了切换特别快。
在一个资源下面,启动了多个轻巧的指令序列,可以来回切,也是程序执行起来的,就是函数呗~Thread
线程保留并发有点,还不用切换消耗特别大。
但是依然要一段程序切换到另一端程序。(线程切换)
进程切换:包括指令切换,和内存的切换。
我们要切换线程,并发,也就是交替执行,cpu的利用率才会上去。
如果读写磁盘,我们就释放cpu去。
yield的目的就是能切换出去,也能切换回来。
注意这边,跟接下来要讲到的细节指令有关系。
第一遍我都看懵了,我们期望就是下图,100的指令,切到300,让它去show,之后我们再回到GetData函数,进行往下走。
(注意上图: 主要是两个执行序列,一个栈,但是这样有问题的,后面会说 )
执行的切换,操作系统的核心!!
A到B执行的话,我们需要跳到b执行,还需要跳回来的,
所以需要把函数返回的地址压栈,用于跳回A方法!
当b执行的时候,yield是一个用户函数,我们自己定义的。
所以我们需要跳到300执行,304压栈,继续往下执行跳转到了D,执行yield,把404压栈。
我们下一个指令序列的话,会进行pc指针,因为400处的yield执行完之后,要回到204
我觉得因为这边Dyield,让出了cpu,所以回到了200;
右大括号} 这个会有汇编指令,弹栈,此时栈顶的地址是404,B函数应该是返回到104处,而不是404处;
这样就会出现问题,
因为ret 结束要返回一个线程内部的函数调用,只能在一个线程内部绕来绕去,
所以应该在左边的框框折腾,为什么会跑到右边去呢,因为两个线程共用了一个栈,
ret不允许到另一个栈里面去,一个函数调用是在一个指令序列内部发生的事,所以每一个指令序列,函数调用应该用自己的栈。所以应该把共用的栈拆开来。
总结:上部分 就是用yield ,进行跳转的手段,然后强行让204之后的返回结果,绕到了另外一个指令序列里面去了,也就是到404弹出栈了,但是这样是不对滴。
那么两个栈:
所以栈是这样滴:
两个tcb对应两个栈。
所以yield,就会栈切回去,所以栈要存放起来,栈的指针,要存放在tcb,全局数据结构
将来切回去,要从tcb找到指针,tcb是cpu里面的寄存器,有点像大脑里面寄了一下,存放了一下地址。
(tips:进程切换其实是一样的。只不过从pcb变成了tcb)
用户级线程,也可以实现切换,由用户主动做的。(完成了一个栈到两个栈,支持了线程的切换,没有进入到内核!)
注意这个东西,大概就是thread 创建的一个过程,
过程:(用户自己的线程,在用户态上来回切来切去,操作系统感知不到它的存在。)
\1. 申请内存做tcb
2.申请内存作为栈 图上是1000
\3. 内存的起止地址放进去
\4. 栈和tcb关联
所以切换的时候首先找到tcb 找到esp,取出值,赋值给真的esp,所以这样弹栈就ok了~
问题:要是一个线程卡了,那么久进程阻塞了。内核需要切换到别的进程,那么这时候,
假如浏览器加载东西的时候,等待网卡IO ,一旦一个用户级的线程卡了,那么就切换到了别的进程,所以有的时候浏览器,切换到了别的标签了,那段程序就不知行了,所以浏览器可能就一块一块的。如果卡了,没有别的进程,那么cpu就会空转了。
核心级的话,需要进入到内核,tcb在内核里面。如果获取数据在内核阻塞,那么缓冲区已经下载了一部分数据,那部分就可以进行执行。
内核级线程就是schedule!调度的特性!内核接管线程,我要调度。
听起来还蛮酷的!
虚拟内存与物理内存之间的映射
用户空间映射到物理内存是独立的,提高安全性
修改内存访问级别 (0是最高级)
MMU是个硬件,每当cpu访问一个地址的时候,MMU从内存里面查table,把cpu想访问的那个虚拟地址转换成物理地址。因为MMU每次查table都要读内存,比较慢,就在内存和MMU之间弄了个缓存,这个缓存就是tlb,里面存着MMU最近访问过的table的内容,如果下次还访问table的这些项的话,就不用读内存里面的table,而是从tlb里面读,这样比较快。
TLB - translation lookaside buffer
快表,直译为旁路快表缓冲,也可以理解为页表缓冲,地址变换高速缓存。
其实就是个缓存;
TCB(transmission control block)传输控制块
可以认为是寄存器吧~如果有不对的可以指正。
当任务重新得到CPU使用权时,TCB能确保任务从被中断的点丝毫不差地继续执行
具体的就不细细研究了
原文地址:https://zhuanlan.zhihu.com/p/576178810
作者:linux