进程


我们都知道知道程序是为了完成某种任务而设计的软件,比如OpenOffice是程序。什么是进程呢?进程就是运行中的程序。一个运行着

的程序,可能有多个进程。举个例子,如果说程序是一个武林秘籍的话,进程就是它的每一招一式。所以进程就是一个运行的程序。同

一个程序可以执行多次,每次都以在内存中开辟独立的空间来装载,从而产生多个进程。不同的进程还可以拥有各自独立的IO接口。

作系统的一个重要功能就是为进程提供方便,比如说为进程分配内存空间,管理进程的相关信息等等现在我们先来看看我们自己电脑

里的进程情况:这里我们使用下面这条命令:


这条命令的意思分别是: -e表示列出全部进程 -o pid,comm,cmd表示我们需要PID,COMMAND,CMD信息 我们现在来看看部分结果:


这只是刚开的一部分进程,后面还有许多许多,我们刚刚说过的PID,COMMAND,CMD分别都是什么东西呢?

PID:每一个进程都有一个唯一的PID来代表自己的身份,进程也可以根据PID来识别其他的进程.

COMMAND:也可以说这就是该进程的名字吧。

CMD:进程所对应的程序以及运行时所带的参数。

 

现在我们来看第一个进程,这个进程呢,它叫init,这个进程很关键的,他是linux启动时的第一个进程,在liunx运行的时候,该进

程会一直存在,这个进程具有一点很重要的意义。

 


进程的创建==>

 

我们现在应该了解到进程是一个什么东西了吧,现在呢我们需要知道这个进程是怎么被创建出来的呢?接下来我们需要了解fork机制这

个东西了,当计算机开机的时候,内核(kernel)只建立了一个init进程。Linux内核并不提供直接建立新进程的系统调用。剩下的所

进程都是init进程通过fork机制建立的。新的进程要通过老的进程复制自身得到,这就是fork。fork是一个系统调用。进程存活

内存中。每个进程都在内存中分配有属于自己的一片空间 。当进程fork的时候,Linux在内存中开辟出一片新的内存空间给新的进程,

并将老的进程空间中的内容复制到新的空间中,此后两个进程同时运行。这里提到的父进程和子进程他们的关系是管理和被管理的关

,当父进程终止时,子进程也随之而终止。但子进程终止,父进程并不一定终止。


老进程成为新进程的父进程,而相应的,新进程就是老的进程的子进程。一个进程除了有一个PID之外,还会有一个PPID来存储的父进

程PID。如果我们循着PPID不断向上追溯的话,总会发现其源头是init进程。所以说,所有的进程也构成一个以init为根的树状结构。

具体我讲到对不对,我们使用pstree命令试验一下,看下面的结果:


[liang@www ~]$ pstree
init─┬─NetworkManager─┬─dhclient
     │                └─{NetworkManager}
     ├─VGAuthService
     ├─abrtd
     ├─acpid
     ├─atd
     ├─auditd───{auditd}
     ├─bluetoothd
     ├─bonobo-activati───{bonobo-activat}
     ├─clock-applet
     ├─console-kit-dae───63*[{console-kit-da}]
     ├─crond
     ├─cupsd
     ├─2*[dbus-daemon───{dbus-daemon}]
     ├─2*[dbus-launch]
     ├─devkit-power-da
     ├─gconfd-2
     ├─gdm-binary─┬─gdm-simple-slav─┬─Xorg
     │            │                 ├─gdm-session-wor─┬─gnome-session─┬─bluetooth-apple
     │            │                 │                 │               ├─gdu-notificatio
     │            │                 │                 │               ├─gnome-panel
     │            │                 │                 │               ├─gnome-power-man
     │            │                 │                 │               ├─gnome-volume-co
     │            │                 │                 │               ├─gpk-update-icon───{gpk-update-ico}
     │            │                 │                 │               ├─metacity───{metacity}
     │            │                 │                 │               ├─nautilus───{nautilus}
     │            │                 │                 │               ├─nm-applet
     │            │                 │                 │               ├─polkit-gnome-au
     │            │                 │                 │               ├─python
     │            │                 │                 │               ├─restorecond
     │            │                 │                 │               └─{gnome-session}
     │            │                 │                 └─{gdm-session-wo}
     │            │                 └─{gdm-simple-sla}
     │            └─{gdm-binary}
     ├─gdm-user-switch
     ├─gnome-keyring-d───2*[{gnome-keyring-}]
     ├─gnome-screensav
     ├─gnome-settings-───{gnome-settings}
     ├─gnome-terminal─┬─bash
     │                ├─bash───pstree
     │                ├─gnome-pty-helpe
     │                └─{gnome-terminal}
     ├─gnote
     ├─gvfs-afc-volume───{gvfs-afc-volum}
     ├─gvfs-gdu-volume
     ├─gvfs-gphoto2-vo
     ├─gvfsd
     ├─gvfsd-burn
     ├─gvfsd-trash
     ├─hald─┬─hald-runner─┬─hald-addon-acpi
     │      │             ├─hald-addon-inpu
     │      │             └─hald-addon-rfki
     │      └─{hald}
     ├─master─┬─pickup
     │        └─qmgr
     ├─5*[mingetty]
     ├─modem-manager
     ├─notification-ar
     ├─polkitd
     ├─pulseaudio─┬─gconf-helper
     │            └─2*[{pulseaudio}]
     ├─rsyslogd───3*[{rsyslogd}]
     ├─rtkit-daemon───2*[{rtkit-daemon}]
     ├─seahorse-daemon
     ├─sshd
     ├─trashapplet
     ├─udevd───2*[udevd]
     ├─udisks-daemon───udisks-daemon
     ├─vmtoolsd───{vmtoolsd}
     ├─vmtoolsd
     ├─vmware-vmblock-───2*[{vmware-vmblock}]
     ├─wnck-applet
     └─wpa_supplicant

 

fork通常作为一个函数被调用。这个函数会有两次返回,将子进程的PID返回给父进程,0返回给子进程。实际上,子进程总可以查询自

己的PPID来知道自己的父进程是谁,这样,一对父进程和子进程就可以随时查询对方。

 

通常在调用fork函数之后,程序会设计一个if选择结构。当PID等于0时,说明该进程为子进程,那么让它执行某些指令。而当PID为一

个正整数时,说明为父进程,则执行另外一些指令。由此,就可以在子进程建立之后,让它执行与父进程不同的功能。

 

进程的分类==>

 

进程基本上分为三类分别为:交互进程,批处理进程,守护进程。

 

值得一提的是守护进程总是活跃的,一般是后台运行,守护进程一般是由系统在开机时通过脚本自动 激活启动或超级管理用户root来启

动。由于守护进程是一直运行着的,所以它所处的状态是等待请求处理任务。比如,我们是不是访问 LinuxSir.Org ,LinuxSir.Org 

的httpd服务器都在运行,等待着用户来访问,也就是等待着任务处理。

 

进程的属性==>

 

进程ID(PID):是唯一的数值,用来区分进程;

父进程和父进程的ID(PPID);

启动进程的用户ID(UID)和所归属的组(GID);

进程状态:状态分为运行R、休眠S、僵尸Z;

进程执行的优先级;

进程所连接的终端名;

进程资源占用:比如占用资源大小(内存、CPU占用量);

 

 

终止进程==>

 

终止一个进程或终止一个正在运行的程序,一般是通过 kill 、killall、pkill、xkill 等进行。比如一个程序已经死掉,但又不能

退出,这时就应该考虑应用这些工具。现在我们先来研究一下子进程被终止的时候,会发生什么?


当子进程终结时,它会通知父进程,并清空自己所占据的内存,并在内核里留下自己的退出信息(如果顺利运行,为0;如果有错误或异

常状况,为>0的整数)。在这个信息里,会解释该进程为什么退出。父进程在得知子进程终结时,有责任对该子进程使用wait系统调用

这个wait函数能从内核中取出子进程的退出信息,并清空该信息在内核中所占据的空间。但是,如果父进程早于子进程终结,子进程就

会成为一个孤儿(orphand)进程。孤儿进程会被过继给init进程,init进程也就成了该进程的父进程。init进程负责该子进程终结时调

用wait函数。


当然,一个糟糕的程序也完全可能造成子进程的退出信息滞留在内核中的状况(父进程不对子进程调用wait函数),这样的情况下,子进

程成为僵尸(zombie)进程。当大量僵尸进程积累时,内存空间会被挤占。


最后再说一句,尽管在UNIX中,进程与线程是有联系但不同的两个东西,但在Linux中,线程只是一种特殊的进程。多个线程之间可以共

内存空间和IO接口。所以,进程是Linux程序的唯一的实现方式。

Logo

更多推荐