操作系统进程和多线程图像

操作系统的进程

操作系统的核心就是管理计算机硬件,包括cpu、内存等等。本文主要记录操作系统如何管理CPU的。

哈工大OS课程链接:https://www.bilibili.com/video/BV1d4411v7u7

1.进程和线程

cpu是如何工作的?取址指令、指令译码、执行。

如何管理cpu?因为cpu工作都是不断的取值执行,我们只需要管理PC的初始地址即可。

这样做有什么问题?

IO指令效率太慢了,如果我们的计算指令中间参杂着IO指令,那么每次执行到IO指令的时候,CPU就会等待IO返回数据,降低了CPU的利用率。浪费了很多时间等IO指令。

所以,操作系统在管理CPU的时候引入了多进程来解决CPU利用率低的问题。

进程就是运行中的程序,操作系统把所有的进程信息都存放在 PCB(Process Control Block) 中,记录进程的运行中状态。所以,一个启动了的程序在操作系统中就是一个进程,然后为了充分的利用CPU,我们启动的多个程序将交替执行,操作系统需要把每个进程的状态记录好,合理的调度资源。操作系统从开机到关机始终记录着所有的进程。

image-20220404182049103

(1)进程切换

上面我们说到,进程执行到一定程度后可能发生阻塞、或者时间片无了,会发起进程切换。操作系统就要切换到别的进程上去执行,但是如果就绪队列上有多个进程,操作系统应该选择谁呢?这就牵扯到了CPU的调度策略。

对于不同的任务,任务之间的关注点都不一样。

比如前台任务可能更关注响应时间短,后台任务关注整体时间端。考虑IO密集型和CPU密集型任务的特点不同,所以CPU调度进程就需要这种考虑各种情况来调度。若响应时间小,则切换次数就要频繁,系统内耗就会变大且吞吐量变小。

所以一个调度算法既要调度的快、又要考虑不同的场景的关注点。

  1. FIFO:先来先服务。
  2. SJF:短作业优先,降低平均周转时间到最小,但是响应时间就不能保证。
  3. RR:按照时间片轮转调度,时间片一到就切换进程,保证响应时间。
  4. Priorty:设置优先级,但是可能进程饥饿。前台任务使用RR,后台任务使用SJF,动态调整任务的优先级。但是后台任务若占用太多时间又会阻塞前台任务的响应时间,所以后台任务也需要时间片限制并兼容优先级。

操作系统中进程的状态如下:

image-20220404184952414

多进程之间的交替,就由就绪、运行、阻塞三个状态中切换。

如何从就绪的进程中选择下一个进程,就称为进程调度,然后就把运行的状态切换为当前的进程,然后再PCB中保存保存上一个进程的状态。操作系统组织进程的形式就是把进程状态放在PCB队列形成进程的交替执行分为:队列操作+调度+切换

PCB里面存储了进程Pid、进程状态、进程资源分配(LDT表)等信息

  • 保存当前的进程状态(PC、寄存器)到PCB,更改进程状态,放入阻塞队列。
  • 切换内核栈,调度下一个进程,更新正在运行的进程,更改进程状态。
  • 更新内存管理的数据结构,PCB信息。
(2)进程通信

进程通信是指进程与进程之间信息交换,但是各个进程的拥有的内存地址是相互独立的,为了保证安全,一个进程是无法访问另一个进程的地址空间的,为了实现进程通信…

操作系统为了实现进程通信,提供了以下方法:共享内存、信号、信号量、管道、消息队列、socket套接字

  • 共享内存:顾名思义,多个进程共享一块儿内存区域,这样就可以一起食用里面的数据了。

  • 信号量:共享内存的时候,多个进程的访问会产生数据的安全问题。所以需要互斥,信号量的PV操作就是其中之一。

  • 消息队列:就是信息传达,进程之间通过发送/接受消息来通信。

  • 管道:管道–用于连接读写进程的一个共享文件(pipe文件)

    管道是内存开辟的一块儿缓冲区,只支持半双工。这个文件如果没有写满就不允许读,没读到空就不允许写。

    对管道进行读操作的时候,读进程必须互斥。

用户级线程

进程是资源分配的最小单位,线程是资源调度的最小单位。一个进程往往包含N个线程,线程之间并发不需要切换系统资源。

#如果一个进程包含多个线程,那么当一个线程阻塞住,进程也会被阻塞

所以我们将线程分为用户级线程和核心级线程,将m个用户级线程和n个内核级线程相映射,解决进程和线程间1:n并发度不够高的问题,也解决了一个进程占用太多核心线程的问题。

image-20220423181542458

用户线程指不需要内核支持而在用户程序中实现的线程,其不依赖于操作系统核心,应用进程利用线程库提供创建、同步、调度和管理线程的函数来控制用户线程。

线程切换不需要用户态/核心态切换,创建和销毁线程、线程切换代价等线程管理的代价比内核线程少得多。

以前网速比较慢的时候,打开浏览器访问一个网页,首先弹出来的是网页的文字部分,然后是一些图片,最后才是一些小视频之类的。为什么呢?浏览器向服务器发起访问的程序是一个进程,它包含若干线程,比如:一个线程用来从服务器接收数据,一个线程用来显示文本,一个线程用来显示文本,一个线程用来显示图片等等。

所以我们有了多线程,上面这个例子就牵涉到线程(用户级线程)的切换,多个线程之间线程的切换只有切换指令。线程中切换指令,用一个TCB(Thread Control Block)要存储一个线程的地址,并且每个线程独有一个栈来存储自己的指令,切换的PC也存入栈中。

用户可以使用yield()函数来再用户态中完成线程的不断切换,每个线程有自己的栈,比如上图A函数调用B函数时,将地址放入线程1的栈1中,同理线程2的地址放在栈2中。切换栈的时候,用TCB将栈1的地址保存起来,esp来保存栈1的栈顶指针。

切换栈的时候只需要更改寄存器esp的值就可以切换栈:

void Yield2()	//线程2切换到线程1
{
	TCB2.esp = esp;			// 保存当前栈顶地址
	esp = TCB1.esp;			// 切换栈			
}

核心级线程

内核线程:由操作系统内核创建和撤销。内核维护进程及线程的上下文信息以及线程切换。一个内核线程由于I/O操作而阻塞,不会影响其它线程的运行。

当线程进行切换的时候,由用户态转化为内核态。切换完毕要从内核态返回用户态。

当有多个处理机时,一个进程的多个内核级线程可以同时执行。

因为想要线程被cpu调度,必须得建立一个TCB,而TCB属于内核数据,想要访问内核数据,必须得要通过系统调用中断 进入内核,而进入内核态执行代码,必须得要一个栈用来保存用户态下的状态

内核级线程的并发性会更好,内核的线程不再受用户控制,完全由操作系统调度。所以在多核cpu中,就是操作核心级线程,将每个线程分配到多核cpu核心上,利用多核CPU处理多线程并行,多核CPU公用一套MMU

本质区别:核心级线程是需要进入到系统内核中执行的程序,核心级线程需要在用户态和核心态里面跑,在用户态里跑需要一个用户栈,在核心态里面跑需要一个核心栈。用户栈和核心栈合起来称为一套栈

img

用户栈和核心栈之间的关联:(这里不太懂,参考即可)

通过INT指令当从用户栈切换到内核栈,把用户占的SSSPPCCS都给保存起来,也就是用户态执行到的位置和指令。然后因为在内核栈中记录了用户栈的状态TCB,所以统称内核线程使用是用户栈和核心栈的一套栈。执行IRET指令切换回去的时候,将这五个栈弹出,随着就退回到用户栈执行的地方。

image-20220405153905929

内核栈切换仍然使用TCB找到内核栈指针,切换内核程序;在CS后面入栈的肯定就是一条指令包含IRET指令,通过栈内的PC:CS切换到用户程序完成程序。

中断(内核线程和用户线程切换)----->可能因为阻塞线程切换----->找TCB完成内核栈切换------->内核栈切换完IRET----->根据栈里面的CS和PC回到用户栈。如果线程S和T不在同一个进程,还需要切换映射表,也就是管理内存。

image-20220405155947501
塞线程切换----->找TCB完成内核栈切换------->内核栈切换完IRET----->根据栈里面的CS和PC回到用户栈。如果线程S和T不在同一个进程,还需要切换映射表,也就是管理内存。

[外链图片转存中…(img-b53bTHyJ-1650710644519)]

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值