[操作系统学习笔记(1)] 多进程图像 CPU工作原理

时间:2022-08-27 16:43:01

管理CPU

        我们通过多进程图像来管理CPU,所以说多进程图像是核心部分。

        那么,操作系统如何管理CPU呢?

[操作系统学习笔记(1)] 多进程图像 CPU工作原理

        总而言之,就是不断的自动取址执行

        一旦给出了第一个地址,后面的地址是自动累加的。


CPU使用率


       我们在程序中执行计算以及一些IO操作。

       前者在电子硬件上完成,后者要涉及到磁盘机械运动。

       一次IO的时间和一次计算的时间比是:10^6 : 1,可见IO操作十分耗时。

       所以对于CPU而言,它执行一个程序时利用率非常低,因为它绝大多数时间都在等待IO操作。而且我们也不能跳过IO语句,因为它可能和接下来的计算相关。

       在这种情况下,CPU的利用率接近于0。


提高使用率方法


         解决这个问题,可以在等待的时候切出去计算别的程序,在一定时候再回来。

         简言之,就是:

        [操作系统学习笔记(1)] 多进程图像 CPU工作原理

        在切换的时候,我们 修改寄存器PC就行了吗?

   事实上,我们还需要记录返回的地址,要记录ax(记录切出去时的状态),也就是“保护现场”,保证CPU以后还能切回来。

        每个程序有了一个存放信息的结构:PCB


进程


       CPU切换的这些程序(运行程序),我们称为进程。

       相比起静态程序,它的特点是:

       [操作系统学习笔记(1)] 多进程图像 CPU工作原理

多进程图像


         操作系统记录进程,并按合理次序分配资源、进行调度,这就是多进程图像。

        为每个进程创建一个结构体:PCB,记录进程的信息。

        从启动开始到关机结束都在执行。


具体过程


        fork()创建第一个进程,init执行shell

        进程shell再启动其它进程

int main(int argc, char* argv[])
{
while(1){
scanf(“%s”,cmd);
if(!fork()){
exec(cmd);
}
wait();
}
}


多进程的组织(PCB,状态,队列)


        一个进程:执行(单一PCB)

        一些进程:等待执行(就绪队列)

        一些进程:等待某事件(比如,磁盘等待队列,在此队列中的,即使在就绪队列中排到了头,也无法执行,因为它的前置条件缺失了)

        使用PCB结构体来组成一些数据结构。


       进程状态图:

      [操作系统学习笔记(1)] 多进程图像 CPU工作原理


        用状态推进多个进程。


多进程的交替


        比较复杂,在这里以一个实例介绍。

        一个进程启动了磁盘读写,它把自己的状态变成阻塞态,操作系统将这个进程放到磁盘等待队列中,再进行交替。

       交替的过程:

       先从就绪队列中找到下一个进程(选择合适的进程是很重要的),让下一进程成为当前活跃的进程。

       总之,就是:

     [操作系统学习笔记(1)] 多进程图像 CPU工作原理

       进程调度:FIFO , 或者设置优先级。


        切出去的时候,把物理CPU的一些重要信息保存到一个PCB中,再把接下来要执行的进程的PCB存到物理CPU中。(需要用汇编代码书写)


多进程之间的影响


        多个进程交替执行,它们都需要被放到内存中。只有这样CPU才能取址执行。

        但是,多个进程放在一起,会出现问题:其中一个进程访问的地址,很有可能是另外一个进程使用的地址,这种访问是破坏性的。

        为了避免这一现象,需要限制某些地址的读写,也就是多进程的地址空间分离。


        基本思想是通过映射表来实现这种分离。

        地址并非真实的地址,而是对应着一个映射,每个进程都有着自己的一个映射表。两个进程虽然访问同一个“地址”,但是由于映射规则不一样,它们实际*问了不同的地址。这样就保证了多个进程在内存*存。


多进程的合作


        举例:打印进程。

        多个文档需要打印的话,先将打印内容放到打印队列,然后再去做别的事情。而打印这边需要从队列中取出内容。

        一个存放内容,一个取出内容,两者之间形成合作关系。

        为了保证合作过程能够有序进行,需要对它们做一些处理,比如组织多个文档按照怎样的顺序进入队列。


        #define BUFFER_SIZE 10

        typedef struct { ....} item;//共享数据

        item buffer[BUFFER_SIZE];

        int in = out = count = 0;


        生产:

        while(true) {

                while( count == BUFFER_SIZE ) ;//如果已满 在这里死循环

                buffer[in] = item; //不满的话直接放入

                in = (in + 1) % BUFFER_SIZE

                count++;

        }

        消费:

        while(true){

                while(count == 0);

                item = buffer[out]; //取出内容

                out = (out + 1)%BUFFER_SIZE;

                count --;


        多个进程都需要修改count。如果切出的时候未能正确修改count的值(还没来得及修改就被切出),就会发生错误。

        所以在修改count的时候,需要将其上锁。也就是说,在一个进程还没修改完count前,不能切换到另一个进程。