(进程)处理过程中的Linux:从执行到退出

      Linux是一个多任务操作系统,表面上看,同时运行许多任务——即进程。每一个进程都在系统中留下足迹。这里介绍一些检查这些足迹的工具,并且还要说明蔓延的/proc目录到底是什么。

    欢迎归来。上周我们考察Linux调度程序如何区分要运行的进程的优先级,并且学习了jiffies(译注:计算机系统时钟滴答声持续时间,约1/100秒)和僵尸进程。现在是考虑一个Linux进程生命周期的时候,还有就在你运行程序时发生什么。

     Linux通过父/子关系强化坚固的家族价值。除一个以外,每一个单独的进程都有一个父进程。这个例外的进程是init,它是其他一切进程的爷爷。它的进程号为1Linux启动时第一个点火的大人物(译注:kahuna的意思有1. Hawaiian shaman: a Hawaiian priest or traditional healer2. important person: an important or influential person)。所有其他进程都是它的产物,不是直接就是从它的后代产生。

    象有些类型的蠕虫和鱼一样,Linux进程只有一个父亲。而且,Linux进程又象豚鼠和野兔一样,几乎可以拥有数不清的子女。

     Linux系统的用户执行命令行命令或者在GUI环境中双击图标和菜单选项时,就创建进程。幕后被调用的应用程序突然活灵活现,因为它们是由一个父进程生下来的——无论这个父进程是BASH shell,例如,还是KDE或者Gnome桌面。

    而且,如果一个程序创建另一个任务,则生成一个属于它自己的子进程。这种情况始终会发生。例如,这正是一个网页请求到达服务器时Apache所做的事情。Apache产生一个新的进程照料接入连接,因而即刻解放(Apache)程序主体,程序就能够收听新的接入请求。如果不生下一个子进程,那么,其他人也许就不能使用这个网络服务器,因为它的时间都花在服务第一个请求,而不是响应新来者。

    在幕后,这些进程几乎是通过Linux内核的三个系统调用之一生成。其中forkvfork这两个分享UNIX遗产,然而,第三个专用于Linux,称为clone

    历史上人们创建新进程首选forkfork系统调用把进程一分为二,留下一个父进程和一个子进程。父进程是原进程,保留它从开始就拥有的进程ID,并接受子进程的ID作为fork的一个返回值。然而,子进程是一个在新的进程空间运行的副本,具有新的进程ID。它接受数值0作为fork的返回值。正是这一个返回值,一旦发生了分离,能让程序代码确定是父进程还是子进程,并且按适合于具体应用程序的无论什么方式作出响应。

     vfork是一项遗物。它类似于fork,除了保证不拷贝用户内存之外。这是打算改进性能和效率。当我说fork制造一个复制品,我真正的意思是:子进程空间的一切完全象原进程一样,除fork返回值之外。硬塞进进程空间里面的所有存储器内容都是复制的。

    一方面,从程序设计的观点看,这是有用的,如果子进程履行其责职必须动用应用程序的历史和当前状态的话。

    然而,另一方面,如果子进程并不真正需要知道所有这些,或者不在意,那么,存储器复制实际上就是浪费的。

    这就是vfork的有用之处;它创造新的子进程而不花费时间读写存储器。init进程在创建它的所有子进程的时候,都调用这个系统调用。任何进程都不必拥有一份init用户态副本,所以,内核开发者认为,象vfork一样的第二个系统调用,对于init的用途和其他象ftpdinetd/xinetd,将是一个有效的两者挑一的选择。

    在实践中,vfork是综合实现的,因为它对子进程提出某些特别要求,使用exec立即调用一个命令,并且这个命令不能失败。如果产下的进程失败,那么结果是不明确的并且从此不可预知。如果核对vfork man page,将找到一些有趣的笔记,包括现存的vfork不幸是一个过去留下的鬼怪!

    所有现代LinuxUNIX发行版都使用一种称为写时复制(copy on write)的技术,这种技术否定vfork存在的必要性,因为现在正规的fork系统调用有了vfork创建子进程带来的效率增益。写时复制促成父子进程尽可能长久地共享物理存储器,只有当其中一个进程实际上写数据到存储器时,才复制内存页。

    如果子进程又创建子进程,而且不写任何内存,则因不需要内存复制而大胜。即使子进程修改一点点内存,也有好处,因为只复制被修改的页。事实上,因为两个进程仅仅需要一个尽可能长久的实际数据集合,所以不仅节省时间,而且节省内存。考虑这给initxinetd以及其他重要系统函数的效益,所有这些的用途基本上是forkexec

     clone系统调用是Linux独有,而且一般用途如fork,但它允许应用程序控制子进程的哪些部分将与父进程共享。

    上面提及的exec是一个基本系统调用。说得更准确些,这是一个系统调用家族,它们的文档在exec man page。在那里列出几个不同的系统调用,但是这些全部都是环绕一个系统调用execve的外包装。

     execve的用途是执行一个命令,或者更明确地说,把进程的控制从一个可执行程序转移到另一个。这就是我们为什么说,initforkexec;它生成一个新的子进程,然后使用exec召唤一个新程序到其位置,不损害原来的父进程。

    那么,关于这个procfs文件系统的所有一切是什么?

    现在,所有这些进程都健康良好,但是如何才能稍稍精细地查明什么正在系统上运行,和重要的进程控制信息。

    答案就是/proc目录,这是一个伪文件系统,呈现所有正在运行的进程的有关信息。用户可以转换到此目录并检查文件,它们好象是基于磁盘的合法文件似的。你不必采用任何更多的工具,便可获得许多有价值的信息。同时,一个程序仅仅使用基本的打开、读、写和关闭等系统调用就能够检查这些内容。

    每个进程都有一个在/proc下面的、按其进程ID命名的子目录。因此,进程ID#1init有一个叫/proc/1的目录,此目录终生存在。另外,还有一个称为/proc/self的特殊目录,它连接到当前运行进程的目录。

每个目录里面是一组文件,提供进程足迹的详细信息。这些大部分是ASCII文本文件。一些比较有趣和比较重要的如下:

cmdline用于调用程序的命令行。命令行被NULL字符(ASCII码值为0)隔断。这是C程序将如何看argv向量。

environ进程环境,串如上。这是C程序如何看envp向量。

      fd 用符号链接指向进程打开的每一个文件描述符的目录。包括磁盘文件、用于网络通信的sockets和进程间通信的管道。这里是你真正获得进程正在干什么的信息的地方。

      oom_score一个保存进程缺少内存得分的文本文件。当Linux用完内存时,它首先杀死高得分进程。

      stat进程状态的单行文本表示。这由ps命令使用。status给出与stat给出一样的信息,但按对人更友好的格式。

      wchan 指出哪一个内核系统调用引起进程阻塞,如果进程处于阻塞状态的话。

    除自己探索这个目录之外,你还可以访问SourceForge procps project项目中的免费工具。这里收集少量有用的使用proc文件系统的实用程序。有些会很熟悉——也就是pskillwtop或者vmstat。有些象slabtopskill对你可能就是新的。

    下次回来还有更多!

你可能感兴趣的:(apache,linux,存储,任务,linux内核,Sockets)