全面剖析《自己动手写操作系统》第六章---进程

转载请标注:http://blog.csdn.net/zgh1988/article/details/7371754

在一开始学习进程的时候,我们大概每个人都会遇到过这样的问题,下面就让我们带着这些问题来认识认识进程。

1、进程是什么?

2、什么是多进程?

3、执行一个进程需要什么?

4、多进程之间是如何调度的?

5、进程的上下文环境是什么?

6、如何创建一个新的进程?

一、进程是什么?

    大家在面试时,有时候会被HR问到这么一道题目:程序与进程有什么区别?

如果让我们通过生硬的概念来回答HR,往往会令HR失望。下面我想通过一个生活中的场景来回答HR这个问题。

周末,张先生想为他心爱的老婆做一道菜---牛肉排骨汤,他有做这道菜的菜谱,厨房里也有牛肉排骨,味精,香料等,张先生就按着菜谱一步步得为他的老婆做好了这道菜---牛肉排骨汤,他的老婆很高兴,感觉很幸福。

在这个比喻中,做牛肉排骨躺的菜谱就是程序,张先生应该就算是处理机(CPU),做这道菜的各种原料(牛肉排骨,大葱等)就是输入数据,一盘香喷喷的牛肉排骨汤则是输出数据,进程就是张先生按着菜谱做好这道菜的整系列动作的总和。

于是我们知道,程序是一个静态的,进程是用来描述动态的过程的。

二、什么是多进程?

    大家都知道,现在的操作系统都是支持多进程的,即一个CPU可以支持多个进程。这个又是什么情况?让我来修改一下上面的场景。

周末,张先生想为他心爱的老婆做一道菜---牛肉排骨汤,他有做这道菜的菜谱,厨房里也有牛肉排骨,味精,香料等,张先生开始做牛肉排骨汤,做着做着,他的儿子的手被刀子划破了,哭着跑到爸爸这里来诉苦,这时候,张先生停下手里的活,在菜谱上记下自己做到了哪里,然后拿出一本急救手册,按着上面的指示,把儿子的手伤包扎好之后,他回到厨房继续做自己的牛肉排骨汤。

在这个场景中,就包含了两个进程,进程一是做牛肉排骨汤,进程二是为儿子包扎伤口。

张先生(CPU)先是执行的进程一,在进程一还米有结束之前,暂停进程一,去执行了进程二。执行完进程二,回到继续执行进程一,直至进程一结束。这个过程就成为进程之间的"切换"。

下面我们通过一张图片来介绍多进程之间的关系:


图(a):一个包含4个进程的进程表

图(b):4个进程是完全独立的

图(c):4个进程进行切换,但任意时刻只有一个进程在运行

由此,我们得知,进程,从宏观上来说,有自己的目标,又受控于进程调度模块的控制。从微观上来说,有自己的代码和数据,同时也拥有自己的堆栈。但又利用系统的资源。

三、执行一个进程需要什么?


每个进程包含自己的代码,数据,和堆栈,并且都服从进程调度模块进行调度。

四、多进程之间是如何调度的?

多进程之间的调度是由进程调度模块来完成的。我们首先需要了解进程的状态,下图为3种状态之间的关系:


在本书中,作者只介绍的是2、3,即就绪--运行--就绪之间的转换关系。其中条件2是调度模块选择其中某一个进程运行。

条件3是时钟中断发生,调度模块将正在运行的进程调入到就绪队列。

五、进程的上下文环境是什么?

    在张先生去为儿子包扎伤口时,他需要在菜谱上记录下自己做牛肉排骨汤做到什么地方,以便回来之后继续做。同理,操作系统在进行系统切换时,也同样要记录下该进程的上下文环境。

于是我们创建了一个数据结构--进程控制块(ProcessControl Block),它主要包括以下几方面信息:

1、进程标识符 name:每个进程都必须有一个唯一的标识符,可以是字符串,也可以是一个数字。

2、进程当前状态 status:说明进程当前所处的状态。为了管理的方便,系统设计时会将相同的状态的进程组成一个队列,如就绪进程队列,阻塞进程则要根据等待的事件组成多个等待队列,如等待打印机队列、等待磁盘I/O完成队列等等。

3、进程相应的程序和数据地址,以便把PCB与其程序和数据联系起来。

4、进程资源清单。列出所拥有的除CPU外的资源记录,如拥有的I/O设备,打开的文件列表等。

5、进程优先级 priority:进程的优先级反映进程的紧迫程度,通常由用户指定和系统设置。

6、CPU现场保护区 cpustatus:当进程因某种原因不能继续占用CPU时(如等待打印机),释放CPU,这时就要将CPU的各种状态信息保护起来,为将来再次得到处理机恢复CPU的各种状态,继续运行。

7、进程同步与通信机制 用于实现进程间互斥、同步和通信所需的信号量等。

8、进程所在队列PCB的链接字 根据进程所处的现行状态,进程相应的PCB参加到不同队列中。PCB链接字指出该进程所在队列中下一个进程PCB的首地址。

9、与进程有关的其他信息。 如进程记账信息,进程占用CPU的时间等。

每个进程有自己的进程控制块,我们将这些进程控制块组织到一起,存储在一个叫进程表(Process Table)的结构数组中。

在本书中,本着简单实用的原则,我们的进程控制块只包含了进程标识符,CPU现场保护(即寄存器的内容),还有局部描述符。程序内容如下:

/* 寄存器 */
typedef struct s_stackframe {
	t_32 gs;	
	t_32 fs;	
	t_32 es;	
	t_32 ds;	
	t_32 edi;	
	t_32 esi;	
	t_32 ebp;	
	t_32 kernel_esp;
	t_32 ebx;		
	t_32 edx;		
	t_32 ecx;		
	t_32 eax;		
	t_32 retaddr;	
	t_32 eip;		
	t_32 cs;		
	t_32 eflags;	
	t_32 esp;	
	t_32 ss;		
}STACK_FRAME;

/* PCB进程控制块 */
typedef struct s_proc {
	STACK_FRAME	regs;			/* 寄存器 */
	t_16		ldt_sel;		/* LDT选择子 */
	DESCRIPTOR	ldts[LDT_SIZE];	        /* LDTs */
	t_32		pid;	                /* 进程号 */
	char		p_name[16];	        /* 名字 */
}PROCESS;

六、如何创建一个新的进程?

    首先我们要申请一个进程控制块(PCB),然后为新的进程分配资源(本程序内为堆栈),继而初始化进程控制块,最后将队列加入就绪队列(本程序即进程表)。

    在本程序内,我们是这样做到的



全面剖析《自己动手写操作系统》第五章--makefile http://blog.csdn.net/zgh1988/article/details/7338380

全面剖析《自己动手写操作系统》第五章---加载内核kernel.bin http://blog.csdn.net/zgh1988/article/details/7329941

全面剖析《自己动手写操作系统》第五章---Red Hat 9.0 的安装过程  http://blog.csdn.net/zgh1988/article/details/7315676

全面剖析《自己动手写操作系统》第四章---FAT12文件系统 http://blog.csdn.net/zgh1988/article/details/7284834

全面剖析《自己动手写操作系统》第四章---加载Loader.bin http://blog.csdn.net/zgh1988/article/details/7291909

全面剖析《自己动手写操作系统》第三章---进入保护模式   http://blog.csdn.net/zgh1988/article/details/7098981

全面剖析《自己动手写操作系统》第三章---“实模式--保护模式--实模式” http://blog.csdn.net/zgh1988/article/details/7255804

全面剖析《自己动手写操作系统》第三章---堆栈段的工作方式 http://blog.csdn.net/zgh1988/article/details/7256254

全面剖析《自己动手写操作系统》第三章---特权级以及不同特权级代码段之间的跳转 http://blog.csdn.net/zgh1988/article/details/7262901

全面剖析《自己动手写操作系统》第三章---分页机制 http://blog.csdn.net/zgh1988/article/details/7270748

全面剖析《自己动手写操作系统》第三章---中断机制 http://blog.csdn.net/zgh1988/article/details/7276259

全面剖析《自己动手写操作系统》第二章http://blog.csdn.net/zgh1988/article/details/7062065

全面剖析《自己动手写操作系统》第一章http://blog.csdn.net/zgh1988/article/details/7060032

《自己动手写操作系统》读后感http://blog.csdn.net/zgh1988/article/details/7059936











 



你可能感兴趣的:(操作系统,自己动手写操作系统)