好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Linux进程基础

Linux进程基础

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢!

计算机实际上可以做的事情实质上非常简单,比如计算两个数的和,再比如在内存中寻找到某个地址等等。这些最基础的计算机动作被称为 指令 (instruction)。所谓的 程序 ( program),就是这样一系列指令的所构成的集合。通过程序,我们可以让计算机完成复杂的操作。程序大多数时候被存储为可执行的文件。这样一个可执行文件就像是一个 菜谱 ,计算机可以按照菜谱作出可口的饭菜。

那么, 程序 和 进程 (process)的区别又是什么呢?

进程是程序的一个 具体实现 。只有食谱没什么用,我们总要按照食谱的指点真正一步步实行,才能做出菜肴。进程是 执行程序 的过程,类似于按照食谱,真正去做菜的过程。同一个程序可以执行多次,每次都可以在内存中开辟独立的空间来装载,从而产生多个进程。不同的进程还可以拥有各自独立的IO接口。

操作系统的一个重要功能就是为进程提供方便,比如说为进程分配内存空间,管理进程的相关信息等等,就好像是为我们准备好了一个精美的厨房。

1. 看一眼进程

首先,我们可以使用 $ps 命令来查询正在运行的进程,比如 $ps -eo pid,comm,cmd ,下图为执行结果:

(-e表示列出全部进程,-o pid,comm,cmd表示我们需要PID,COMMAND,CMD信息)

 

每一行代表了一个进程。每一行又分为三列。第一列 PID (process IDentity) 是一个整数,每一个进程都有一个唯一的PID来代表自己的 身份 ,进程也可以根据PID来识别其他的进程。第二列COMMAND是这个进程的简称。第三列CMD是 进程所对应的程序 以及运行时所带的参数。

(第三列有一些由中括号[]括起来的。它们是kernel的一部分功能,被打扮成进程的样子以方便操作系统管理。我们不必考虑它们。)

 

我们看第一行,PID为1,名字为init。这个进程是执行/bin/init这一文件(程序)生成的。当 Linux启动 的时候, init 是系统创建的第一个进程,这一进程会一直存在,直到我们关闭计算机。这一进程有特殊的重要性,我们会不断提到它。

 

2. 如何创建一个进程

实际上,当计算机开机的时候,内核(kernel)只建立了一个init进程。Linux  kernel并不提供直接建立新进程的 系统调用 。 剩下的所有进程都是init进程通过fork机制建立的。新的进程要通过老的进程 复制自身 得到,这就是 fork 。fork是一个系统调用 。进程存活于内存中。每个进程都在内存中分配有属于自己的一片空间 (address space)。当进程fork的时候,Linux在内存中开辟出一片新的内存空间给新的进程,并将老的进程空间中的内容复制到新的空间中,此后两个进程同时运行。

老进程成为新进程的父进程(parent process),而相应的,新进程就是老的进程的子进程(child process)。一个进程除了有一个PID之外,还会有一个 PPID (parent PID)来存储的父进程PID。如果我们循着PPID不断向上追溯的话,总会发现其源头是init进程。所以说,所有的进程也构成一个以init为根的树状结构。

如下,我们查询当前shell下的进程:

root@vamei:~#  ps  - o pid,ppid,cmd
  PID  PPID CMD
  16935    3101   sudo  - i
  16939   16935  - bash
  23774   16939   ps  -o pid,ppid,cmd

我们可以看到,第二个进程bash是第一个进程sudo的子进程,而第三个进程ps是第二个进程的子进程。

fork通常作为一个函数被调用。这个函数会有两次返回,将子进程的PID返回给父进程,返回0给子进程。实际上,子进程总可以查询自己的PPID来知道自己的父进程是谁,这样,一对父进程和子进程就可以随时查询对方。

通常在调用fork函数之后,程序会设计一个if选择结构。当PID等于0时,说明该进程为子进程,那么让它执行某些指令,比如说使用exec库函数(library function)读入某一个程序文件,在当前进程的空间中执行(这实际上是我们使用fork的一大目的: 为程序创建进程);而当PID不为0时,说明为父进程,则执行另外一些指令。由此,就可以在子进程建立之后,让它执行与父进程不同的功能。

 

3.子进程的终结(termination)

当子进程终结时,它会通知父进程,并清空自己所占据的内存,并在kernel里留下自己的 退出信息 (exit code)。在这个信息里,会解释该进程为什么退出。父进程在得知子进程终结时,有责任对该子进程使用 wait 系统调用(从程序员的角度来说,是一个函数) 。这个wait函数能从kernel中 取出子进程的退出信息 ,并清空该信息在kernel中所占据的空间。但是,如果父进程早于子进程终结,子进程就会成为一个 孤儿 (orphand)进程。孤儿进程会被过继给init进程,init进程也就成了该进程的父进程。init进程负责该子进程终结时调用wait函数。

当然,一个糟糕的程序也完全可能造成子进程的 退出信息始终滞留在kernel中 的状况(父进程不对子进程调用wait函数),这样的情况下,子进程成为 僵尸 (zombie)进程。当大量僵尸进程积累时,内存空间会被挤占。

 

4.进程与线程(thread)

尽管在UNIX中,进程与线程是不同的两个东西,但在Linux中,线程只是一种特殊的进程。多个线程之间可以共享内存空间和IO接口。所以,进程是Linux程序的唯一的实现方式。

 

总结:

程序,进程,PID,内存空间

子进程,父进程,PPID,fork, wait

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢!

 

标签:  Linux

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于Linux进程基础的详细内容...

  阅读:37次