系统进程管理

  • 在Unix中,所有信息都由某个文件或程序提供,简单来说,文件只是个输入输出对象,而一个进程才是执行的对象

本章将搞懂 :

  • 进程从哪来?进程如何被系统控制?如何控制自己的进程?

系统如何控制进程

  • 准确说:进程是一个被装载到内存的程序,全部的程序数据、信息也会被放入内存中。

所有的进程被内核kernel管理,当一个进程创建时,内核指定一个 Process ID(identification number)给进程,以便追踪进程信息。

    • 内核会管一个进程信息表,由**PID和进程名构成,**有了这个表,内核将掌握控制进程的必要信息。

小型Unix系统可以同时执行100多进程,大Unix可达到上千进程。

Cpu time

先介绍Cpu time, 以前电脑只有一个cpu,而单个cpu要面对不同进程任务,为了雨均沾,给每个进程设置一个cputime 如10毫秒。cpu从 等待执行的进程列表中选出一个进程,让其执行10毫秒,时间一到就选出下一个进程,而上一个进程就要记录当前运行的状态,以便下次再继续。

System call

当一个程序要执行时,要向内核(kernel)发出一条call,让系统准备不同操作

  • 最重要的system calls 有fork exec wait exit

fork

fork 用来创建一个当前进程的复制进程,源进程为父进程,复制的进程为子进程

wait

wait 可以将进程暂停

exec

exec 可以将当前正在执行的进程改变成其他进程

exit

exit 退出当前进程(如,对刚登陆的shell使用,则会退出) shell本身也是个进程,也有PID

1
2
可以用echo $$ 查看当前shell的PID
1509615

kill 用来结另一个进程

一个进程如何被执行

Unix有两种命令 内部和外部命令,内部命令是内置在Unix中的,所以不用创建新的进程

对于外部命令或外部程序,以下为Unix执行过程

在shell中输入一个sl命令

则Unxi会用fork(system call ) 创建一个当前进程的复制进程(子进程) ,

  • 然后将子进程用exec将当前进程改变到要执行的外部命令sl
  • 同时,将父进程用wait暂停执行,直到子进程完成.

进入shell后打开文档进行编辑也是这个过程,父进程将等待到vim退出编辑

  • 在子进程结束后,将执行exit,然后转到父进程中。并将子进程所用的文件、内存全部释放,让其它进程再使用,此时,像子进程这种已经失效的进程成为Zombie ,在进程表中仍然保留其信息,当父进程恢复后,可以查看子进程在进程表的信息,随后系统将自动将信息删除。

Q:上面提到了fork 可以创建一份复制进程和一个父进程,但如何辨识两个进程是父还是子进程?

A:fork对父进程产生一个返回值(return value) 是进程原PID ,对子进程返回0

最初的进程 init

Q:既然所有进程都由fork创建的子进程,那终极父进程是谁?

A:init进程

unix启动时

系统会**”手动“创建一个特殊进程**(不用fork创建),并给一个PID为0#0)被称为”空闲进程“

  • 他执行一些重要功能如初始化数据
  • 随后**#0进程开始分枝(fork)出进程#1**

#1被#0分支出来的,就是init进程,而init进程会打开系统的控制台并挂载到根文件系统

然后#1运行/etc/inittab这里的shell脚本,执行脚本过程中,#1用fork产生子进程来执行不同命令,如让用户登陆

  • 随后**#0进入无限循环不做任何事**件(名字由来)
  • 当目前无任何进程时,系统将进入#0进程,并不做任何事。

综上所述

#0这个空闲进程才是真正的终极父进程,#1 init也是个子进程,但考虑到#0完成任务后就消失了(不做任何事,但进程还运行runing),因此,将#1称为 在活着的(living) 终极父进程

如果某个父进程在子进程结束前先没了,子进程将变成(orphans)孤儿,但init将领养这个孤儿,让他继续完成未完成的任务。

前台和后台进程

后台进程(background)

让进程自己运行,不用监看他运行,shell将不会等待进程完成,就会提示输入下一条命令

后台的进程也被称为自治进程

如:

要对一大堆数据排序,要花较长时间,则可以让进程自己运行,人可以再执行一些其它命令。可以用&(ampersan) 实现,告诉进程让他自己运行不用交互。

在一般命令后添加一个&

1
sort < file > res & 

如果一行有多个命令

1
(sleep 5;cat /etc/passwd) & #要用括号包起来

前台进程(foreground)

shell将等进程完成后再让输入下一命令

后台进程注意点

  • 对于某些需要在进程执行还要输入信息的情况,如果进程得不到输入,就会一直等待到有输入,这时可以用:

fg命令 将此进程移到前台并输入相关信息

  • 后台正在的进程会将输出到监视器指定要某个文件中(推荐)
  • 后台进程的输入会被用/dev/nul代替,并且无法用ctrl+c或其它方式中断。当然,可以用kill 来结束后台进程

当后台进程完成时,shell会发送一条信息如

1
[1] Done ls>temp #表示进程完成

当然,shell不会不识相的突然打断正在进行的工作并发出这条提醒,而在下一次正常提示其它命令信息时附加这条完成信息

  • 不想要提示信息
1
2
set -o notify 就没了
set +o notify 就有了

sleep命令#让进程延迟启动

语法

1
sleep interval[s|m|h|d]   #interval是延迟时间

1
2
3
sleep 5 5秒(默认以秒为单位)
sleep 5m 5分钟
sleep 20;cat /etc/prasswd & 表示在后台等待20秒,随后将passwd复制到屏幕前

jobs命令#显示全部的工作 #1/#2/#3

1
ps process status #显示全部进程

ctrl + Z 将当前进程悬挂

echo $$显示当前shell 的PID

echo $! 显示上一个被移动到后端的命令

fg命令#将job移动到前端

语法

  • fg %[job]
1
fg %num #则为通用方法

若不添加**[job]**则恢复当前正在执行的job(有+)

或者可以用某个命令开头

1
fg %make / fg %m /fg %?game

再或者

1
fg %+ / fg %-

%常用表

%% 当前job

%+ 当前job

%- 之前job

%n job#n

%name 用具体名字

%?name 命令的一部分

[8]- running make game > res &

[1]+ running gcc program.c &

举例:正在执行vim 编辑,突然想查找cal,可以将vim悬挂到后台按ctrl+z,在shell中输入cal 再将vim从后台中fg出来

ctrl+z 后,shell给出一条提示,表示job#1 被停止

1
[1]+ Stopped vim testf   #表示testf已经停止

fg %或fg %vim 后可以恢复vim testf

suspend命令#将当前shell悬挂

ctrl+z 可以将job悬挂到后台,除了当前shell。如想将当前shell也悬挂,要用suspend

功能:

  • 将当前shell悬挂,可以快速切换不同的身份

语法

  • suspend [-f]

举例

  • 在bash shell下开了tcsh
  • 在tcsh下,可以用suspend悬挂tcsh并bg到原bash

多任务同时协作

jobs展示目前执行的

语法:

  • jobs [-l]
1
2
jobs
[1] Stopped vim testf (被悬挂了)
  • jobs -l 可以显示进程PID
1
2
jobs -l
[1]+ 2288 Stopped vim testf
  • 其中的+表示,current job正在执行的job
  • 对应的-表示 之前的job

bg命令#将job移动到后端

语法

  • bg [%job]

用法和fg一样,%后可以接数字、命令、命令部分

bg一般配合ctrl+z 使用,如在等待某个程序输出时,此时不能输入命令,按ctrl+z 将进程悬挂,再输入bg 将进程放入后台。

ps命令#查看进程信息

(process status) 查看进程信息

语法

  • ps [-aefFly] [-p pid] [-u uid ]

选项

显示哪些文件

  • -a 将userid与进程相关
  • -e (everything)全部的进程包含系统进程
  • -p pid 查找指定PID
  • -u uid 查找UID
  • -t 只显示系统进程

显示哪些数据

  • 默认 PID TTY TIME CMD
  • 常用 -f UID PID PPID C TTY TIME CMD
  • -ly S UID PID PPID C PRI NI RSS SZ WCHAN TTY TIME CMD

TTY是终端名

CMD是正在执行的命令

TIME是使用cpu时间

PID是当前进程id

PPID是父进程id

WCHAN 等待的状态?有wait/finish等值

S 状态 R runing T suspended S waiting

SZ 物理大小(占用内存情况)

ps -ef 常用,可以查看全部的进程并包含UID

使用ps 查找非系统进程,再显示出PID后再用ps -f -p 1234 显示具体信息

1
2
3
4
5
ps
1548435 pts/0 00:00:00 ps
ps -f -p 1548435
UID PID PPID C STIME TTY TIME CMD
root 1522200 1522175 0 13:44 pts/0 00:00:00 -bash

top命令#实时监视系统进程

功能:

  • top可以展示系统实时变化的信息
  • 按h可以查看按键帮助

语法:

  • top -d delay -n count [-p pid[,pid]]

选项

  • -d 1 每隔1秒刷新 /0.1s
  • -p PID 可以显示某个进程详细信息
  • -p -d 1 -p 1,2,3,4,5 可以展示多个PID

pstree命令

功能:

  • 展示进程树

上文提到过 :每个进程都由其它进程复制的,源进程为父,新进程为子,而且子进程也有PID

#0被手动创建后,fork出子进程#1,再由#1执行各种操作,产生其它进程#3.4.5

而这些#3,4,5被称为守护进程,任务是等待事件发生并做出反馈

登陆进程会一直等着用户登陆,一旦用户登陆,登陆进程会创建新进程来执行shell

而shell又会执行命令,创建新进程

于是,每个进程便有唯一的父进程,整个进程系统可以用一棵树结构表示

语法

  • pstree [-aAcGnpu] [pid|userid]

选项

  • -p PID 指定PID/UID 将展示属于UID的(全部)进程
  • -n 按PID排序
  • -a 展示整个命令行
  • -u 在子进程与父进程不同UID时标记

举例

  • 用ps或echo $$查出当前shell的PID,再用pstree -p PID查出当前sh的结构
1
2
3
4
5
echo $$
1539825
pstree -p 1539825
bash(1522200)---vim(1528516)---bash(1528529)---pstree(1528530)
#可以看到 当前bash下开的命令 vim 后面的bash说明在进行vim后又打开了一个bash

Unix如何管理文件和进程

  • 文件有文件系统,有文件树,根是root/ 每个文件有I-number 查看文件信息时,用ls 只要查看文件的I-node就行
  • 进程有进程系统,进程树,根是#1 init 每个进程有PID 查看进程时,用ps/top 要在进程所在的/proc目录下,找到进程对应文件,再从文件中读取出信息

Q:那有什么命令可以打通文件与进程的关系吗?fuser

A:可以列出每个进程所用到的文件

1
2
3
4
find ./ -name '*.mp3' >bar 2>/dev/null &   #让find在后台查找全部的mp3 把输出给bar
[1] 2233 #表示当前进程PID
fuser bar #查询bar文件,可以得到
bar:2233 #说明当前文件被2233进程使用

kill命令#给job发送一个信号

  • 给其它进程发送信号
  • 停止一个进程 对某些进程不能用ctrl+c停止时(如后台进程)

停止进程

语法

  • kill [-9] PID | jobid

  • kill 2233或像fg/bg一样
  • kill %vim
  • kill %+ 停止当前运行进程

如果kill也失效 -9 强制停止,保证一定会停止

kill -9 2233 ----但此方法不会让进程释放使用的资源,可能会导致文件错误关闭,要少用

发送信号

kill本来是用于给不同进程发送信号的,但默认下发送结束进程信号,所以被叫做kill

语法

  • kill [-signal] pid | jobid

使用kill -l可以查看全部的信号