通常在命令行键入某个程序文件名以后,一个进程就被创建了。例如:
范例:让程序在后台运行
$ sleep 100 &
[1] 9298
范例:查看进程 ID
用pidof
可以查看指定程序名的进程ID:
$ pidof sleep
9298
范例:查看进程的内存映像
$ cat /proc/9298/maps
08048000-0804b000 r-xp 00000000 08:01 977399 /bin/sleep
0804b000-0804c000 rw-p 00003000 08:01 977399 /bin/sleep
0804c000-0806d000 rw-p 0804c000 00:00 0 [heap]
b7c8b000-b7cca000 r--p 00000000 08:01 443354
...
bfbd8000-bfbed000 rw-p bfbd8000 00:00 0 [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]
程序被执行后,就被加载到内存中,成为了一个进程。上面显示了该进程的内存映像(虚拟内存),包括程序指令、数据,以及一些用于存放程序命令行参数、环境变量的栈空间,用于动态内存申请的堆空间都被分配好。
实际上,创建一个进程,也就是说让程序运行,还有其他的办法,比如,通过一些配置让系统启动时自动启动程序(具体参考 man init
),或者是通过配置 crond
(或者 at
)让它定时启动程序。除此之外,还有一个方式,那就是编写 Shell 脚本,把程序写入一个脚本文件,当执行脚本文件时,文件中的程序将被执行而成为进程。这些方式的细节就不介绍,下面了解如何查看进程的属性。
需要补充一点的是:在命令行下执行程序,可以通过 ulimit
内置命令来设置进程可以利用的资源,比如进程可以打开的最大文件描述符个数,最大的栈空间,虚拟内存空间等。具体用法见 help ulimit
。
查看进程的属性和状态
可以通过 ps
命令查看进程相关属性和状态,这些信息包括进程所属用户,进程对应的程序,进程对 cpu
和内存的使用情况等信息。熟悉如何查看它们有助于进行相关的统计分析等操作。
范例:通过 ps 命令查看进程属性
查看系统当前所有进程的属性:$ ps -ef
查看命令中包含某字符的程序对应的进程,进程 ID
是 1 。 TTY
为?表示和终端没有关联:
$ ps -C init
PID TTY TIME CMD
1 ? 00:00:01 init
选择某个特定用户启动的进程:
$ ps -U falcon
按照指定格式输出指定内容,下面输出命令名和 cpu
使用率:
$ ps -e -o "%C %c"
打印 cpu
使用率最高的前 4 个程序:
$ ps -e -o "%C %c" | sort -u -k1 -r | head -5
7.5 firefox-bin
1.1 Xorg
0.8 scim-panel-gtk
0.2 scim-bridge
获取使用虚拟内存最大的 5 个进程:
$ ps -e -o "%z %c" | sort -n -k1 -r | head -5
349588 firefox-bin
96612 xfce4-terminal
88840 xfdesktop
76332 gedit
58920 scim-panel-gtk
范例:通过 pstree 查看进程亲缘关系
系统所有进程之间都有“亲缘”关系,可以通过 pstree
查看这种关系:$ pstree
会打印系统进程调用树,可以非常清楚地看到当前系统中所有活动进程之间的调用关系。
范例:用top动态查看进程信息
$ top
该命令最大特点是可以动态地查看进程信息,当然,它还提供了一些其他的参数,比如 -S
可以按照累计执行时间的大小排序查看,也可以通过 -u
查看指定用户启动的进程等。
补充: top
命令支持交互式,比如它支持 u
命令显示用户的所有进程,支持通过 k
命令杀掉某个进程;如果使用 -n 1
选项可以启用批处理模式,具体用法为:
$ top -n 1 -b
范例:确保特定程序只有一个副本在运行
下面来讨论一个有趣的问题:如何让一个程序在同一时间只有一个在运行。这意味着当一个程序正在被执行时,它将不能再被启动。那该怎么做呢?
假如一份相同的程序被复制成了很多份,并且具有不同的文件名被放在不同的位置,这个将比较糟糕,所以考虑最简单的情况,那就是这份程序在整个系统上是唯一的,而且名字也是唯一的。这样的话,有哪些办法来回答上面的问题呢?
总的机理是:在程序开头检查自己有没有执行,如果执行了则停止否则继续执行后续代码。
策略则是多样的,由于前面的假设已经保证程序文件名和代码的唯一性,所以通过 ps
命令找出当前所有进程对应的程序名,逐个与自己的程序名比较,如果已经有,那么说明自己已经运行了。
ps -e -o "%c" | tr -d " " | grep -q ^init$ #查看当前程序是否执行
[ $? -eq 0 ] && exit #如果在,那么退出, $?表示上一条指令是否执行成功
每次运行时先在指定位置检查是否存在一个保存自己进程 ID
的文件,如果不存在,那么继续执行,如果存在,那么查看该进程 ID
是否正在运行,如果在,那么退出,否则往该文件重新写入新的进程 ID
,并继续。
pidfile=/tmp/$0".pid"
if [ -f $pidfile ]; then
OLDPID=$(cat $pidfile)
ps -e -o "%p" | tr -d " " | grep -q "^$OLDPID$"
[ $? -eq 0 ] && exit
fi
echo $$ > $pidfile
#... 代码主体
#设置信号0的动作,当程序退出时触发该信号从而删除掉临时文件
trap "rm $pidfile" 0
更多实现策略自己尽情发挥吧!