转载请标注: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