首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

历程基础知识

2012-09-29 
进程基础知识Java码农学底层学习《深入理解Java虚拟机》接近尾声,对12.4节中描述的操作系统中的线程实现很感

进程基础知识


Java码农学底层
学习《深入理解Java虚拟机》接近尾声,对12.4节中描述的操作系统中的线程实现很感兴趣。所以就趁热打铁,继续看《Operating System Concept》(恐龙书操作系统概念)和《Linux内核设计与实现》两本经典操作系统图书。前者偏重理论,在每章知识点讲解结束后会对各个操作系统的实现加以指点,而后者则是对Linux的具体实现,一个个具体代码片段进行分析,细致入微。于是在此做些总结,融合这两本书中的内容,留作日后深入学习《深入Linux内核》的参考。
中断:操作系统的神经,不仅响应外界(键盘、鼠标、网卡等各种IO设备的输入数据)的请求,并且还定时触发系统定时器(削减时间片等)和动态定时器(中断处理程序的下半部The Half Bottom)。《操作系统概念》中将现代操作系统称为中断驱动的系统一点都不为过,因此将中断比喻成操作系统及其管理的硬件这个庞大野兽躯体内的神经名副其实。
进程:如果说CPU是操作系统乃至整个PC机的大脑,那么进程就是实际去完成大脑意志的肉体了。任意时刻都至少有一个进程在运转着,按照CPU中指令的要求完成动作。这个操作系统中最重要的概念之一涉及了很多内容:生命周期、调度、通信、同步、安全保护等等。本篇是对进程基础知识的总结,算是开篇吧,之后再逐一学习高级的内容。

进程的结构
一个进程包括了程序计数器、堆、栈、代码(TextSection)、全局变量(DataSection)等。在栈和堆之间的空闲内存可能会被开辟出来作为进程间通信的共享内存区(关于进程间通信IPC的知识在以后会学习到)。
对Java虚拟机来讲,它也只不过是操作系统管理的众多进程中的一个,没有什么特别之处。JVM自己管理着从操作系统申请来的堆空间和数据区,将其作为内存堆和方法区供所有内部的线程共享。同时JVM中的线程拥有各自私有的PC程序计数器、Java方法栈等。
历程基础知识

Linux的进程描述符是task_struct,被保存在双向循环链表中(在下一篇讨论进程调度时将会看到它是如何保存的)。通过遍历这个链表及task_struct中的parent和children指针,我们就可以得到当前所有进程的父子关系(见后面讨论的进程创建),当然在用户空间中我们是没法访问内核的数据结构的,这需要我们改写内核的源码,在内核态操作,还是先学好基础再弄高级的吧。:)
历程基础知识

既然这些task_struct是被单独保存在一个链表中供内核使用的,那么各个进程是如何关联到它的呢?在每个进程地址空间的底部(低地址)都有一个thread_info结构,其中保存了指向该进程的task_struct的指针。这样做就可以通过栈指针计算出task_struct而不用额外的寄存器专门记录了。这对于像x86这样寄存器并不富裕的体系结构来说是种优化,在内核栈的尾端创建thread_info结构,通过计算偏移间接地查找task_struct结构。但对于寄存器富裕的体系结构,完全可以用一个专门寄存器存放指向当前进程的task_struct结构。
历程基础知识


进程的状态
对于单任务系统来讲,进程只需新建、运行、终止三种状态就够了。因为进程在运行过程中不会因为阻塞而进入其他状态,无论如何其他进程都要等到当前进程执行完毕后才能开始。
但在多任务系统中,当进程发生阻塞时内核会让当前进程休眠,让其他进程启动,从而使CPU一直保持运转。因此多任务系统的进程还需要一个等待(waiting)状态。
在多任务分时系统中,一个进程即便没有发生阻塞也不可能一直占用CPU,所有进程要共享CPU资源,不断切换执行。所以分时系统的进程还需要一个准备(ready)状态。
所以现代操作系统中的进程状态可以归纳为下图:
历程基础知识

任意时刻一个CPU上只有一个进程能处于running状态。但Linux中的ready和running状态都用TASK_RUNNING来表示。
历程基础知识


进程的创建
Windows和Unix/Linux的进程创建方法很不同,首先来看Windows的进程创建。在Windows中我们通过调用CreateProcess()函数创建子进程,传入的参数中包含了子进程要执行的exe文件路径。此外还会传递一些进程的属性信息作为参数。



进程的继承关系
下面是Solaris系统启动后的进程树,init进程下有两个子进程。dtlogin进程是一个登录用户,通过X-windows(Xsession)操作Solaris,打开了C-shell执行ls、cat等命令。另一个进程inetd,通过telnet服务为另一个用户开启C-shell,并打开Netscape和emacs等程序。在Unix-like系统中,我们可以通过ps或pstree来查看当前进程信息。
历程基础知识

前面Windows创建进程的例子中,在CreateProcess()之后,父子进程之间便没有关系了。但在Linux中父子进程是有很强的继承关系的,所以当父进程在子进程之前退出,这些子进程就会变成孤儿,所以内核还要为它们找到新的父进程,如果找不到就会让init进程作为它们的父进程。而当子进程已经完成但父进程还没有调用wait()获得其返回值时,子进程便处于TASK_ZOMBIE僵尸状态了。由于父子进程间联系较弱,所以Windows没有这两个问题。

热点排行