前言
提示:以下是本篇文章正文内容
一、CPU工作原理
CPU工作原理很简单,就是不断的取指执行。CPU根据PC寄存器中的值到内存中取指令,PC会自动+1,当执行完本条指令后,CPU又根据PC寄存器取指执行。
所以我们让CPU执行一段程序最直接的做法就是让PC的值设置为程序的起始地址,这样CPU会自动的执行这段程序直到程序结束。
CPU的工作原理:取指执行(自动的取指执行)
但是如果我们不对CPU进行管理,会导致CPU的利用率较低。
int main(int argc, char* argv[])
{
int i , to, *fp, sum = 0;
to = atoi(argv[1]);
for(i=1; i<=to; i++)
{
sum = sum + i;
fprintf(fp,“%d”, sum);
}
}
//执行时间为 0.30521424865722897
int main(int argc, char* argv[])
{
int i , to, *fp, sum = 0;
to = atoi(argv[1]);
for(i=1; i<=to; i++)
{
sum = sum + i;
}
}
//执行时间为: 0.006346824075317383
从上面可以看到相同的循环次数,但IO任务的执行时间远远大于计算任务,但在执行IO任务时,CPU是空闲的,此时CPU利用率很低。我们可以让CPU在这段时间里忙碌起来,这就要我们对CPU进行管理。
当将PC的值设置为程序的起始地址,如果不对CPU进行管理,让CPU自动的取指执行,如果程序有大量的IO任务时,CPU的利用率极低,所以我们要对CPU进行管理,提高CPU的利用率
CPU管理
当在执行IO任务时,此时CPU处于空闲状态,我们可以将CPU分配给其他程序使用,当IO任务完成时,CPU又切换到该程序继续执行。
管理:核心是任务的切换,内存存放多个程序,多个程序交替执行
CPU的利用率将会提高:
任务切换:当一个程序执行IO任务时,把PC的值设置为另一个程序的执行地址就可以去执行另一个程序,然后IO任务完成,又切回原来的程序执行
但是,如何在让CPU切换回来呢?
运行中的程序会有一个称为PCB的数据结构,这个数据结构是用来记录当前程序运行的状态信息的,在进行任务切换时,将一些必要的信息压栈(如CS,IP),然后要切换回来时,出栈(恢复成切换任务前的状态),即可以让当前PC指针指向原来的程序位置,继续运行。
二、多进程
1.引入进程
进程:进程是进行(执行) 中的程序(CPU的管理是为了提高CPU的利用率,提高的核心思想就是多道程序交替执行,为了实现多道程序交替执行,通过进程来管理程序的运行)
进程和程序区别:
1.进程是有状态的。有开始、结束等运行状态,而程序没有。
2.进程会记录一些寄存器的值,这些值就是上下文。
3.进程会走走停停,程序没有这个概念。
2.多进程
多进程图像:启动多个程序,交替执行,能充分利用CPU,启动了的的程序就是进程,多个进程的推进,操作系统只要把这些进程记录好,按照合理的次序推进(分配资源,进行调度)
多进程图像一直存在于操作系统启动到关机的整个过程中
操作系统在启动时开的第一个进程是shell或者windows桌面,shell再启动其他进程
启动shell程序:
//一个命令启动一个进程, 返回shell再启动其他进程
int main(int argc, char * argv[])
{
while(1)
{
scanf(“%s”, cmd);
if(!fork())
{
exec(cmd);
}
wait();
}
}
shell程序中在等待输入命令(CMD),有命令输入后就启动该命令对应的进程,然后返回shell再等待启动其他进程。如下图所示:
3.多进程的组织
多进程的组织:PCB + 状态 + 队列
每个进程都有个PCB(progress control block)来记录该进程的信息,操作系统依赖PCB来感知该进程,通过对PCB的感知将进程排入不同的队列,放在不同的状态中。如图
三种不同的队列分别对应==运行态、就绪态、阻塞态。==操作系统控制进程在不同状态间切换将他们同时推进。形成如下状态图
多进程的交替
多进程交替: 队列操作+调度+切换
启动磁盘的读写为例:
启动磁盘读写;
pCur.state = ‘W’;
将pCur放到DiskWaitQueue(磁盘等待队列);
schedule();
schedule()
{
pNew = getNext(ReadyQueue);
switch_to(pCur,pNew);
}
pCur是PCB的里面的信息,w表示阻塞态。先将当前进程的状态置为阻塞态,将该进程放进磁盘等待队列。然后启动调度函数(schedule)来切换到下一个进程,其中getnext就是从就绪队列中取下一个将要执行的进程,switch完成切换
进程切换
//上下文切换
switch_to(pCur,pNew)
{
//保存正在进行的程序
pCur.ax = CPU.ax;
pCur.bx = CPU.bx;
...
pCur.cs = CPU.cs;
pCur.retpc = CPU.pc;
//将要运行的程序压入CPU中
CPU.ax = pNew.ax;
CPU.bx = pNew.bx;
...
CPU.cs = pNew.cs;
CPU.retpc = pNew.pc;
}
保存当前现场,恢复下个程序的现场然后执行下个程序。
4.多进程的影响
1.内存管理
由于内存中同时存在多个进程的,多个进程在交替,那么如图中进程1在访问地址100,而地址一百正是进程2开始的地方,进程2很可能还没有完成,就切到了进程1,如果在进程1中地址100处的内容被修改了,那么切回进程2时程序就出错了。
解决的办法:限制对地址100的读写
多进程的地址空间分离:内存管理的主要内容
通过进程的地址映射实现进程间的地址空间分离
进程1的映射表将访问限制在进程1范围内,进程1根本访问不到其他进程的内容。也就是[100]只是逻辑上的地址,其对应一篇内存上的物理地址,即使不同进程间都有逻辑地址100,但其对应的物理空间不同
2.多进程合作
打印任务1看到就绪队列空了后,就把自己放了进去,这时打印任务2也看了就绪队列空了,也想把自己放进去,此时任务1还没放完,进插入了任务2,那么7上同时由两个任务的内容,打出来不就是乱码
所以,在处理共享资源时,可以给共享的资源进行上锁。等待该资源被开锁,下一个进程才能使用
总结
提示:这里对文章进行总结: