PHP 进程详解
如下内容从《操作系统精髓与设计原理》中总结提炼得出,删除了大部分对于理解进程有干扰的文字,对进程知识结构进行的梳理。几乎所有内容为按照书本上摘抄下来的,我目前还总结提炼不出像作者这么深刻的见解。那么就先学习等完全理解透了,再用自己的语言表达出来。它山之石,可以攻玉。
进程的概念是操作系统的结构的基础。Multics的设计者在20世纪60年代首次使用了这个技术词语,它比作业更通用一些。关于进程的定义,如下所示:
1.一个正在执行的程序。
2.计算机中正在运行的程序的一个实例。
3.可以分配给处理器并由处理器执行的一个实体。
4.由单一的顺序的执行线程、一个当前状态和一组相关的系统资源所描述的活动单元。
也可以把进程当成由一组元素组成的实体,进程的两个基本的元素是程序代码
(可能被执行相同程序的其他进程共享)和代码相关联的数据集
。假设处理器开始执行这个程序代码,且我们把这个执行实体叫做叫做进程
。在进程执行时,任意给定一个时间,进程都可以唯一的被表征为以下元素。
1.标识符:跟这个进程相关的唯一标识符,用来区别其他进程。
2、状态:如果进程正在执行,那么进程处于运行态。
3、优先级:相对于其他进程的优先级
4、内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享内存块的指针。
5、上下文数据:进程执行时处理器的寄存器中的数据。
6、I/O 状态信息:包括显示的I/O操作。分配给进程的I/O设备(例如磁带驱动器)和被进程使用的文件列表等。
7、记账信息:可能包括处理器时间综合、使用的是时钟数总和、时间限制、记账号等。
如下图:
1、为什么设计了进程?
设计出一个能够协调各种不同活动的系统软件是非常困难的。在任何时刻都有许多作业在运行中,每个作业都包括要求按照顺序执行的很多步骤,因此分析时间的序列组合是不可的。由于缺乏能够在所有活动中进行协调和合作的系统级的方法,程序员只能基于他们对操作系统所控制的环境的理解,采用自己的特殊方法。然而这种方法是很脆弱的,尤其对于一些程序设计中的小错误,因为这些错误只有在很少见的时间序列发生时才会出现。由于需要从应用程序软件错误和硬件错误中区分出这些错误,因而诊断工作是很困难的。及时检测出错误,也很难确定原因,因为很难在线错误产生的精确场景。一般而言,产生这类错误的4个主要原因如下:
1.不正确同步
2.失败互斥。
3.不确定的程序操作
4.死锁
以上详细描述请参阅:《操作系统精髓与设计原理》第六版第二章或查看网页版】
解决这些问题需要一种系统级别的方法监控处理器中不同程序的执行。进程的概念为
此提供了基础。
因此进程可以看做是由三部分组成的:
1.一段可以执行的程序
2.程序所需要的相关数据
3.程序的执行上下文
2、了解进程执行上下文
执行上下文是进程的重重之中。执行上下文(execution context)
又称作进程状态(process state)
,是操作系统用来管理和控制进程所需的内部数据。这种内部信息和进程是分开的,因为操作系统信息不允许被进程直接访问。上下文包括操作系统管理进程以及处理器正确执行进程所需要的所有信息。包括了各种处理器寄存器的内容,如程序计数器和数据寄存器。它还包括操作系统使用的信息,如进程优先级以及进程是否在等待特定 I/O事件的完成。
图1
图1 两个进程A 和B ,存在于内存中某部分。也就是说给每个进程(包含程序、数据和上下文信息)分配一块存储器区域,并且在由操作系统建立和维护的进程表中进行记录。进程表中包含记录每个进程的表现,表项内容包括指向包含进程的存储块地址的指针,还包括该进程的部分或全部执行上下文。指向上下文的其余部分存放在别处,可能和进程自己保存在一起,通常也可能保存在内存里一块独立的区域中。进程索引寄存器(process index register)
包含当前正在控制处理器的进程在进程表中的索引。程序计数器
指向该进程中下一条待执行的指令。基址寄存器(base register)
和界限寄存器(limit register)
定义了该进程所占据的存储器区域:基址寄存器
中保存了该存储器区域的开始地址,界限寄存器
中保存了该区域的大小(以字节或字为单位)。程序计数器和所有的数据引用相对于基址寄存器
被解释,并且不能超过界限寄存器
中的值,这就可以保护内部进程间不会相互干涉。(解决了互斥的问题)
图1进程索引寄存器
表明进程B正在执行。以前执行的进程被临时中断,在A中断的同时,所有的寄存器的内容被记录在它执行上下文环境中,以后操作系统就可以执行进程切换,恢复进程A的执行。进程切换过程包括保存B的上下文和恢复A的上下文。当在程序计数器
中载入指向A的程序区域的值时,进程A自动恢复执行。
因此进程被当做数据结构来实现。一个进程可以是正在执行,也可是等待执行。任何时候整个进程状态都包含在它的执行上下文环境中。这个结构使得可以开发功能强大的技术,以确保在进程中进行协调和合作。在操作系统中可能会设计和并入一些新的功能(优先级,linux中nice值。)这可以通过扩展上下文环境以包括支持这些特征的新信息。
3、两状态进程模型
操作系统的基本职责是控制进程的执行。这包括确定交替执行的方式和给进程分配资源在设计控制进程的程序时,第一步就是描述进程所表现出的行为。
由前面的基础知识介绍可知,在任何时刻,一个进程要么正在执行,要么没有执行,因而可以构造最简单的模型。一个进程可以处于以下两种状态之一:运行态或未运行态。当操作系统创建一个新的进程时,它将该进程运行态加入到系统中,操作系统知道这个进程是存在的,并且正在等待执行机会。当前正在运行的进程时不时的被中断,操作系统中的分派器
部分将选择一个新进程运行。前一个进程从运行态转换到未运行状态,另外一个集成转换到运行态。如下图.
从这个简单的模型可以意识到操作系统的一些设计元素。必须用某种方式来表示每个进程,使得操作系统能够跟踪它,也就是说,必须有一些与进程相关的信息,包括进程在内存中的当前状态和位置,即进程控制块
。未运行的进程必须保持在某种类型的队列中,并等待它们的执行时机。结构中有一个队列,队列中的每一项都指向某个特定进程的指针,或队列可以由数据块构成的链表组成,每个数据块表示一个进程。如下图
因此可以用该队列图描述分派器
的行为。被中断的进程转移到等待进程队列中,或者,如果进程已经结束或取消,则被销毁(离开系统)。在任何一种情况下,分派器
均从队列中选择一个进程来执行。
4、进程的创建和终止
进程创建
传统地,操作系统创建进程的方式对用户和应用程序都是透明的,这在当代操作系统中也很普遍。但是允许一个进程引发另一个进程的创建将是很有用的。例如一个程序进程可以产生另一个进程,以接受应用程序产生的数据,并将数据组织成适合以后分析的格式。新进程与应用程序并行
的运行,并当得到新的数据时被激活。这个方案对于构造应用程序是非常有用的,例如,服务器进程(如打印服务器、文件服务器)可以为它处理的每个请求产生一个新进程。当操作系统为另一个进程的显式请求产生一个新进程时,这个动作称为进程派生。
当一个进程派生另一个进程时,前一个称作父进程
,被派生的进程称作子进程
。在典型的情况下,相关进程需要像话之间通信和合作。对程序员来说,合作是一个非常困难的任务。
进程终止
以下事件会导致进程终止,尤其注意最后两种事件。父进程终止与父进程请求终止子进程。
5、进程的五状态模型
如果所有的进程都做好了执行准备。队列是先进先出(first-in-first-out)
的表,对于可运行的进程处理器以一种轮转(round-robin)
方式操作(依次给队列中的每个进程一定的执行时间,然后进程返回队列,阻塞情况除外)。但是存在着一些非运行状态但已经就绪等待执行的进程,而同时存在另外的一些处于阻塞状态等待I/O操作结束的进程。因此,如果使用单个队列,分派器不能只考虑队列中最老的进程,相反,他应该扫描这个列表,查找那些被阻塞且在队列中时间最长的进程。
解决这种情况的一种比较自然的方法是将非运行状态分成两个状态:就绪(ready)
和阻塞(blocked)
,此外应该增加两个已经证明很有用的状态。
运行态:该进程正在执行。假设计算机只有一个处理器,因此一次最多只有一个进程处于这个状态。
就绪态:进程做好了准备,只要有机会就开始执行。
阻塞/等待态:进程在某些事件发生前不能执行,如I/O操作完成。
新建态:刚刚创建的进程,操作系统还没有把它加入到可执行进程组中。通常是进程控制块已经创建但还没有加载到内存中的新进程。
退出态:操作系统从可执行进程组中释放出的进程,或者是因为它自身停止了,或者是因为某种原因被取消。
新建态
和退出态
对进程管理是非常有用的。新建状态对应于刚刚定义的进程。例如,如果一位新用户试图登录到分时系统中,或者一个新的批作业被提交执行,那么操作系统可以分两步定义新进程。首先,操作系统执行一些必需的辅助工作,将标识符关联到进程,分配和创建管理进程所需要的所有表。此时,进程处于新建状态,这意味着操作系统已经执行了创建进程的必需动作,但还没有执行进程。
例如,操作系统可能基于性能或内存局限性的原因,限制系统中的进程数量。当进程处于新建态时,操作系统所需要的关于该进程的信息保存在内存中的进程表中,但进程自身还未进入内存,就是即将执行的程序代码不在内存中,也没有为与这个程序相关的数据分配空间。当进程处于新建态时,程序保留在外存中,通常是磁盘中。
类似地,进程退出
系统也分为两步。首先,当进程到达一个自然结束点时,由于出现不可恢复的错误而取消时,或当具有相应权限的另一个进程取消该进程时,进程被终止;终止使进程转换到退出态,此时,进程不再被执行了,与作业相关的表和其他信息临时被操作系统保留起来,这给辅助程序或支持程序提供了提取所需信息的时间。一个实用程序为了分析性能和利用率,可能需要提取进程的历史信息,一旦这些程序都提取了所需要的信息,操作系统就不再需要保留任何与该进程相关的数据,该进程将从系统中删除。
6、UNINX的独特进程
UNINX 中有两个独特的进程。进程0是一个特殊的进程,实在系统启动时创建的。实际上,这是预定义的一个数据结构,在启动时被加载,是交换进程。此外,进程0产生进程1,称作初始进程,进程1是系统中的所有其他进程的祖先。当新的交互用户登录到系统是,由进程1为该用户创建一个用户进程。随后,用户进程可以创建子进程,从而构成一棵分支书,因此任何应用程序都是由一组相关进程组成的。
7、进程控制结构:
此部分对于了解线程特别重要。
此部分对于了解线程特别重要。
此部分对于了解线程特别重要。
一个进程至少包括足够的内存空间,以保存该进程的程序和数据;此外,程序的执行通常涉及用于跟踪过程调用和过程间参数传递的栈。最后,与每个进程相关联的还有操作系统用于控制进程的许多属性,通常:
属性的集合称作进程控制块
。
程序、数据、栈、属性的集合称作进程映像
下图经过了我的重新绘制,希望能够比书本上更加易懂。
以上为进程控制块、进程映像的关系。后续的文章会继续沿着进程、线程的方向去走。争取整理出一套涉及PHP进程、子进程、线程、协程的相关理论与实践文章。
吃饭去喽。