16.1 什么是程序 (process)

由前面一连几个章节的数据看来,我们一直强调在 Linux 下面所有的指令与你能够进行的动作都与权限有关, 而系统如何判定你的权限呢?当然就是第十三章帐号管理当中提到的 UID/GID 的相关概念,以及文件的属性相关性啰!再进一步来解释,你现在大概知道,在 Linux 系统当中:“触发任何一个事件时,系统都会将他定义成为一个程序,并且给予这个程序一个 ID ,称为 PID,同时依据启发这个程序的使用者与相关属性关系,给予这个 PID 一组有效的权限设置。” 从此以后,这个 PID 能够在系统上面进行的动作,就与这个 PID 的权限有关了!

看这个定义似乎没有什么很奇怪的地方,不过,您得要了解什么叫做“触发事件”才行啊! 我们在什么情况下会触发一个事件?而同一个事件可否被触发多次?呵呵!来了解了解先!

16.1.1 程序与程序 (process & program)

我们如何产生一个程序呢?其实很简单啦,就是“执行一个程序或指令”就可以触发一个事件而取得一个 PID 啰!我们说过,系统应该是仅认识 binary file 的,那么当我们要让系统工作的时候,当然就是需要启动一个 binary file 啰,那个 binary file 就是程序 (program) 啦!

那我们知道,每个程序都有三组人马的权限,每组人马都具有 r/w/x 的权限,所以:“不同的使用者身份执行这个 program 时,系统给予的权限也都不相同!”举例来说,我们可以利用 touch 来创建一个空的文件,当 root 执行这个 touch 指令时,他取得的是 UID/GID = 0/0 的权限,而当 dmtsai (UID/GID=501/501) 执行这个 touch 时,他的权限就跟 root 不同啦!我们将这个概念绘制成图示来瞧瞧如下:

程序被载入成为程序以及相关数据的示意图图16.1.1、程序被载入成为程序以及相关数据的示意图

如上图所示,程序一般是放置在实体磁盘中,然后通过使用者的执行来触发。触发后会载入到内存中成为一个个体,那就是程序。 为了操作系统可管理这个程序,因此程序有给予执行者的权限/属性等参数,并包括程序所需要的指令码与数据或文件数据等, 最后再给予一个 PID 。系统就是通过这个 PID 来判断该 process 是否具有权限进行工作的!他是很重要的哩!

举个更常见的例子,我们要操作系统的时候,通常是利用连线程序或者直接在主机前面登陆,然后取得我们的 shell 对吧!那么,我们的 shell 是 bash 对吧,这个 bash 在 /bin/bash 对吧,那么同时间的每个人登陆都是执行 /bin/bash 对吧!不过,每个人取得的权限就是不同!也就是说,我们可以这样看:

程序与程序之间的差异图16.1.2、程序与程序之间的差异

也就是说,当我们登陆并执行 bash 时,系统已经给我们一个 PID 了,这个 PID 就是依据登陆者的 UID/GID (/etc/passwd) 来的啦~以上面的图 16.1.2 配合图 16.1.1 来做说明的话,我们知道 /bin/bash 是一个程序 (program),当 dmtsai 登陆后,他取得一个 PID 号码为 2234 的程序,这个程序的 User/Group 都是 dmtsai ,而当这个程序进行其他作业时,例如上面提到的 touch 这个指令时, 那么由这个程序衍生出来的其他程序在一般状态下,也会沿用这个程序的相关权限的!

让我们将程序与程序作个总结:

  • 程序 (program):通常为 binary program ,放置在储存媒体中 (如硬盘、光盘、软盘、磁带等), 为实体文件的型态存在;

  • 程序 (process):程序被触发后,执行者的权限与属性、程序的程序码与所需数据等都会被载入内存中, 操作系统并给予这个内存内的单元一个识别码 (PID),可以说,程序就是一个正在运行中的程序。

  • 子程序与父程序:

在上面的说明里面,我们有提到所谓的“衍生出来的程序”,那是个啥咚咚?这样说好了,当我们登陆系统后,会取得一个 bash 的 shell ,然后,我们用这个 bash 提供的接口去执行另一个指令,例如 /usr/bin/passwd 或者是 touch 等等,那些另外执行的指令也会被触发成为 PID ,呵呵!那个后来执行指令才产生的 PID 就是“子程序”了,而在我们原本的 bash 环境下,就称为“父程序”了!借用我们在第十章 Bash 谈到的 export 所用的图示好了:

程序相关系之示意图图16.1.3、程序相关系之示意图

所以你必须要知道,程序彼此之间是有相关性的!以上面的图示来看,连续执行两个 bash 后,第二个 bash 的父程序就是前一个 bash。因为每个程序都有一个 PID ,那某个程序的父程序该如何判断?就通过 Parent PID (PPID) 来判断即可。此外,由第十章的 export 内容我们也探讨过环境变量的继承问题,子程序可以取得父程序的环境变量啦! 让我们来进行下面的练习,以了解什么是子程序/父程序。

例题:请在目前的 bash 环境下,再触发一次 bash ,并以“ ps -l ”这个指令观察程序相关的输出信息。答:直接执行 bash ,会进入到子程序的环境中,然后输入 ps -l 后,出现:

F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000 13928 13927  0  80   0 - 29038 wait   pts/0    00:00:00 bash
0 S  1000 13970 13928  1  80   0 - 29033 wait   pts/0    00:00:00 bash
0 R  1000 14000 13970  0  80   0 - 30319 -      pts/0    00:00:00 ps

有看到那个 PID 与 PPID 吗?第一个 bash 的 PID 与第二个 bash 的 PPID 都是 13928 啊, 因为第二个 bash 是来自于第一个所产生的嘛!另外,每部主机的程序启动状态都不一样, 所以在你的系统上面看到的 PID 与我这里的显示一定不同!那是正常的!详细的 ps 指令我们会在本章稍后介绍, 这里你只要知道 ps -l 可以查阅到相关的程序信息即可。

很多朋友常常会发现:“咦!明明我将有问题的程序关闭了,怎么过一阵子他又自动的产生? 而且新产生的那个程序的 PID 与原先的还不一样,这是怎么回事呢?”不要怀疑,如果不是 crontab 工作调度的影响,肯定有一支父程序存在,所以你杀掉子程序后, 父程序就会主动再生一支!那怎么办?正所谓这:“擒贼先擒王”,找出那支父程序,然后将他删除就对啦!

  • fork and exec:程序调用的流程

其实子程序与父程序之间的关系还挺复杂的,最大的复杂点在于程序互相之间的调用。在 Linux 的程序调用通常称为 fork-and-exec 的流程 [1]!程序都会借由父程序以复制 (fork) 的方式产生一个一模一样的子程序, 然后被复制出来的子程序再以 exec 的方式来执行实际要进行的程序,最终就成为一个子程序的存在。 整个流程有点像下面这张图:

程序使用 fork and exec 调用的情况示意图图16.1.4、程序使用 fork and exec 调用的情况示意图

(1)系统先以 fork 的方式复制一个与父程序相同的暂存程序,这个程序与父程序唯一的差别就是 PID 不同! 但是这个暂存程序还会多一个 PPID 的参数,PPID 如前所述,就是父程序的程序识别码啦!然后(2)暂存程序开始以 exec 的方式载入实际要执行的程序,以上述图示来讲,新的程序名称为 qqq ,最终子程序的程序码就会变成 qqq 了! 这样了解乎!

  • 系统或网络服务:常驻在内存的程序

如果就我们之前学到的一些指令数据来看,其实我们下达的指令都很简单,包括用 ls 显示文件啊、用 touch 创建文件啊、rm/mkdir/cp/mv 等指令管理文件啊、chmod/chown/passwd 等等的指令来管理权限等等的,不过, 这些指令都是执行完就结束了。也就是说,该项指令被触发后所产生的 PID 很快就会终止呢! 那有没有一直在执行的程序啊?当然有啊!而且多的是呢!

举个简单的例子来说好了,我们知道系统每分钟都会去扫瞄 /etc/crontab 以及相关的配置文件, 来进行工作调度吧?那么那个工作调度是谁负责的?当然不是鸟哥啊! 呵呵!是 crond 这个程序所管理的,我们将他启动在背景当中一直持续不断的运行, 套句鸟哥以前 DOS 年代常常说的一句话,那就是“常驻在内存当中的程序”啦!

常驻在内存当中的程序通常都是负责一些系统所提供的功能以服务使用者各项任务,因此这些常驻程序就会被我们称为:服务 (daemon)。系统的服务非常的多, 不过主要大致分成系统本身所需要的服务,例如刚刚提到的 crond 及 atd ,还有 rsyslogd 等等的。还有一些则是负责网络连线的服务,例如 Apache, named, postfix, vsftpd... 等等的。这些网络服务比较有趣的地方,在于这些程序被执行后,他会启动一个可以负责网络监听的端口 (port) ,以提供外部用户端 (client) 的连线要求。

鸟哥的图示

Tips 以 crontab 来说,他的主要执行程序名称应该是 cron 或 at 才对,为啥要加个 d 在后面?而成为 crond, atd 呢?就是因为 Linux 希望我们可以简单的判断该程序是否为 daemon, 所以,一般 daemon 类型的程序都会加上 d 在文件名后头~包括服务器篇我们会看到的 httpd, vsftpd 等等都是 ^_^。

16.1.2 Linux 的多用户多任务环境

我们现在知道了,其实在 Linux 下面执行一个指令时,系统会将相关的权限、属性、程序码与数据等均载入内存, 并给予这个单元一个程序识别码 (PID),最终该指令可以进行的任务则与这个 PID 的权限有关。根据这个说明,我们就可以简单的了解,为什么 Linux 这么多用户,但是却每个人都可以拥有自己的环境了吧!^_^ !下面我们来谈谈 Linux 多用户多任务环境的特色:

  • 多人环境:

Linux 最棒的地方就在于他的多用户多任务环境了!那么什么是“多用户多任务”?在 Linux 系统上面具有多种不同的帐号, 每种帐号都有都有其特殊的权限,只有一个人具有至高无上的权力,那就是 root (系统管理员)。除了 root 之外,其他人都必须要受一些限制的!而每个人进入 Linux 的环境设置都可以随着每个人的喜好来设置 (还记得我们在第十章 BASH 提过的 ~/.bashrc 吧?对了!就是那个光!)!现在知道为什么了吧?因为每个人登陆后取得的 shell 的 PID 不同嘛!

  • 多任务行为:

我们在第零章谈到 CPU 的速度,目前的 CPU 速度可高达几个 GHz。 这代表 CPU 每秒钟可以运行 109 这么多次指令。我们的 Linux 可以让 CPU 在各个工作间进行切换, 也就是说,其实每个工作都仅占去 CPU 的几个指令次数,所以 CPU 每秒就能够在各个程序之间进行切换啦! 谁叫 CPU 可以在一秒钟进行这么多次的指令运行。

CPU 切换程序的工作,与这些工作进入到 CPU 运行的调度 (CPU 调度,非 crontab 调度) 会影响到系统的整体性能! 目前 Linux 使用的多任务切换行为是非常棒的一个机制,几乎可以将 PC 的性能整个压榨出来! 由于性能非常好,因此当多人同时登陆系统时,其实会感受到整部主机好像就为了你存在一般! 这就是多用户多任务的环境啦![2]

  • 多重登陆环境的七个基本终端窗口:

在 Linux 当中,默认提供了六个文字界面登陆窗口,以及一个图形界面,你可以使用 [Alt]+[F1].....[F7] 来切换不同的终端机界面,而且每个终端机界面的登陆者还可以不同人! 很炫吧!这个东西可就很有用啦!尤其是在某个程序死掉的时候!

其实,这也是多任务环境下所产生的一个情况啦!我们的 Linux 默认会启动六个终端机登陆环境的程序,所以我们就会有六个终端机接口。 您也可以减少啊!就是减少启动的终端机程序就好了。 未来我们在开机管理流程 (第十九章) 会再仔细的介绍的!

  • 特殊的程序管理行为:

以前的鸟哥笨笨的,总是以为使用 Windows 98 就可以啦!后来,因为工作的关系,需要使用 Unix 系统,想说我只要在工作机前面就好,才不要跑来跑去的到 Unix 工作站前面去呢!所以就使用 Windows 连到我的 Unix 工作站工作!好死不死,我一个程序跑下来要 2~3 天,唉~偏偏常常到了第 2.5 天的时候, Windows 98 就给他挂点去!当初真的是给他怕死了~

后来因为换了新计算机,用了随机版的 Windows 2000 ,呵呵,这东西真不错 (指对单人而言) ,在死机的时候, 他可以仅将错误的程序踢掉,而不干擾其他的程序进行,呵呵! 从此以后,就不用担心会死机连连啰!不过,2000 毕竟还不够好,因为有的时候还是会死当!

那么 Linux 会有这样的问题吗?老实说, Linux 几乎可以说绝对不会死机的!因为他可以在任何时候, 将某个被困住的程序杀掉,然后再重新执行该程序而不用重新开机!够炫吧!那么如果我在 Linux 下以文字界面登陆,在屏幕当中显示错误讯息后就挂了~动都不能动,该如何是好!? 这个时候那默认的七个窗口就帮上忙啦!你可以随意的再按 [Alt]+[F1].....[F7] 来切换到其他的终端机界面,然后以 ps -aux 找出刚刚的错误程序,然后给他 kill 一下,哈哈,回到刚刚的终端机界面!恩~棒!又回复正常啰!

为什么可以这样做呢?我们刚刚不是提过吗?每个程序之间可能是独立的,也可能有相依性, 只要到独立的程序当中,删除有问题的那个程序,当然他就可以被系统移除掉啦!^_^

  • bash 环境下的工作管理 (job control)

我们在上一个小节有提到所谓的“父程序、子程序”的关系,那我们登陆 bash 之后, 就是取得一个名为 bash 的 PID 了,而在这个环境下面所执行的其他指令, 就几乎都是所谓的子程序了。那么,在这个单一的 bash 接口下,我可不可以进行多个工作啊? 当然可以啦!可以“同时”进行喔!举例来说,我可以这样做:

[root@study ~]# cp file1 file2 &

在这一串指令中,重点在那个 & 的功能,他表示将 file1 这个文件复制为 file2 ,且放置于背景中执行, 也就是说执行这一个命令之后,在这一个终端接口仍然可以做其他的工作!而当这一个指令 (cp file1 file2) 执行完毕之后,系统将会在你的终端接口显示完成的消息!很便利喔!

  • 多用户多任务的系统资源分配问题考虑:

多用户多任务确实有很多的好处,但其实也有管理上的困扰,因为使用者越来越多, 将导致你管理上的困扰哩!另外,由于使用者日盛,当使用者达到一定的人数后, 通常你的机器便需要升级了,因为 CPU 的运算与 RAM 的大小可能就会不敷使用!

举个例子来说,鸟哥之前的网站管理的有点不太好,因为使用了一个很复杂的人数统计程序, 这个程序会一直去取用 MySQL 数据库的数据,偏偏因为流量大,造成 MySQL 很忙碌。 在这样的情况下,当鸟哥要登陆去写网页数据,或者要去使用讨论区的资源时, 哇!慢的很!简直就是“龟速”啊!后来终于将这个程序停止不用了, 以自己写的一个小程序来取代,呵呵!这样才让 CPU 的负载 (loading) 整个降下来~ 用起来顺畅多了! ^_^