文章目录
1 多个进程使用CPU的图像
思考:
如何使用CPU?
让程序执行起来
如何充分利用CPU?
启动多个程序,交替执行
启动了的程序就是进程,所以是多个进程推进
OS只需要把这些进程记录好,要按照合理的次序推进(分配资源,进行调度),这就是多进程图像
用户只关心实际的多进程运行的如何,而OS负责具体的多进程推进
多进程图形从机器启动到关机结束
在机器启动过程时,main.c函数中,main初始化各种设备后,将使用fork()创建第一个进程,即shell/Windows来提供给用户使用计算机,shell/Windows再启动其它进程,一个命令启动一个进程,返回shell再启动其它进程
Windows中通过任务管理器观察进程:
OS通过管理进程来管理用户对计算机的使用
2 多进程如何组织
操作系统感知与组织进程全靠PCB,PCB用来记录进程信息的数据结构
多进程通过PCB将进程放在不同队列中,用状态转化来推进多进程
由于CPU只有一个,同一时刻只能为一个进程服务,可以类比为食堂打饭排队,每个同学是一个进程,队列最前面的同学正在打饭,即有一个进程正在被CPU服务,后面有一系列进程等待,它们处于就绪队列,还有一些同学虽然在队列里,但是他们找不到饭卡就不能打饭,即该进程需要等待某事件,才能得到CPU的服务
多进程的组织:PCB+状态+队列
进程状态图:
为了更好管理这些进程,根据它们的状态进行分类,类比银行中,窗口中正在办理业务的就处于运行态,座位上等待的人处于就绪态,人太多去门口等座位的处于阻塞态,结束服务的处于终止态,刚到银行想办理业务的处于新建态,这些状态全都是由OS来管理的,OS管理好这些状态,对进程的状态进行改变,就整体推进了多进程
进程状态图能给出进程生存期的清晰描述,它是认识操作系统进程管理的一个窗口
3 多进程如何交替切换
交替的三个部分:队列操作+调度+切换
OS通过schedule()来进行进程间的切换:
schedule()中最为重要的是 getNext(),它将从就绪队列中取出一个进程,接下来swithc进行当前进程和取出的进程切换,CPU转去服务取出的进程,getNext负责极为重要的 调度,调度有若干种方式
4 进程调度
交替的三个部分:队列操作+调度+切换,调度是最为重要的
调度的两种简单方式:
1,FIFO(先到先出):
FIFO是公平的策略,但却没有考虑到进程执行任务
2,Priority(优先级):
FIFO过于简单,可以为各个进程赋予优先级,如简单进程优先处理,但优先级该如何设定,且优先级会使某些进程饥饿,仍是问题
5 进程切换
切换进程可以类比为,大脑是CPU,你正在读书即进程1,突然有电话接入,这时需要将读书的位置即第几页第几行记住保存在大脑中,即对应进程1的PCB1中,这时来电话的是同事,他向你询问工作上的一些问题即进程2,你需要将这些信息从这段回忆的PCB2中拿出来,放到大脑中进行处理,等到处理完这些事,取出PCB1的内容,大脑得知书读到了第几页第几行,继续进程1的处理
切换通过switch_to(pCur,pNew)实现:
其核心是寄存器内的值的保存与赋值
6 多进程之间如何影响
由于多个进程之间的程序都放在内存中,当多个进程同时存在时会产生一些问题:
对于上面问题的解决方法:限制对地址100的读写,通过映射表进行多进程的地址空间分离
各个进程通过各自的进程映射表来访问真实的物理内存,从而实现地址空间分离,使得多进程在内存中和平相处
多进程的地址空间分离是内存管理的主要内容,进程管理连带内存管理形成多进程图像
7 多进程之间如何合作
对于一个打印的工作过程:
1,应用程序提交打印任务
2,打印任务被放进打印队列
3,打印进程从队列中取出任务
4,打印进程控制打印机打印
对于这个待打印文件队列,有的进程想要打印一个.pdf,有的进程想打印一个.word,这些进程的PCB向待打印文件队列存放,打印机的打印进程来取,一个个根据调度来处理,这就完成了多进程之间的合作
对于待打印队列中的7号空位置,进程1和进程2想要处理打印任务,如果不合作可能一开始进程1将它的一部分信息存入,切换到进程2,进程2将一部分信息存入一部分,如果进程间不合作,那么就会乱套
8 消费者和生产者问题
将上面打印的问题抽象一下,将向待打印队列中放的进程作为生产者,将从待打印对列中取的进程作为消费者,将待打印队列作为共享数据
生产者生产数据存入共享数据,消费者从共享数据中取出数据处理,共享数据的容量有限作为缓冲区使用
生产者进程向缓冲区中送入数据(in),消费者从缓冲区中取出数据(out),生产者和消费者进行合作操作缓冲区,缓冲区的大小为BUFFER_SIZE,其中counter的存在控制了缓冲区中数据的个数以防止缓冲区溢出,造成数据出错
但多个进程都放在内存中交替执行,counter就会出问题:
上面生产者和消费者对counter处理的理想情况是,counter初始值为5,当生产者送入1个数据到缓冲区,消费者从缓冲区中取出一个数据,counter=counter+1-1=5
但由于多进程交替执行可能会出现:
上面是一种可能的执行过程,初始时刻counter=5,当生产者向buffer中送入了数据后,生产者对应的counter寄存器+1,但是还没来得及将counter+1写入counter内,就切换到了消费者进程,此时消费者的counter寄存器得到的counter值仍是5,消费者取出数据,将counter-1存放到消费者counter寄存器中,但此时又切换到了生产者进程,生产者将counter+1写入counter中,此时counter=6,但又切换到了消费者进程,消费者将counter-1写入counter中,此时counter=4,但实际上counter=5,这样就造成了缓冲区的混乱,进程之间的合作就会乱套
9 进程间合作在于进程同步(合理的推进顺序)
对于上述的生产者和消费者问题中counter的问题,为了解决多进程切换对counter的改动,所以在写counter时阻断其它进程访问counter
OS对于多进程的推进不是随意推进,而是合理的推进