进程管理 - d09¶
第一课 编程基础
第二课 内存管理
第三课 文件系统
第四课 进程管理
第五课 信号处理
第六课 进程通信
第七课 网络通信
第八课 线程管理
第九课 线程同步
第十课 综合案例
------------------
一、基本概念¶
1.进程与程序
1)进程就是运行中的程序。一个运行着的程序,
可能有多个进程。进程在操作系统中完成特定的任务。
进程是一个内存的概念,就是内存中的一个数据块,其中包括代码和数据。
2)程序是存储在磁盘上,
包含可执行的机器指令和数据的静态实体。
进程或任务是处于活动状态的程序。
程序是一个文件的概念,其中包含了代码和数据。
2.进程的分类
1)交互进程:通过一个人机界面与用户交换信息。
2)批量进程:在无人值守的情况下,集中执行一个复杂而且耗时的任务。
3)守护进程(幽灵进程/精灵进程)
3.查看进程
1)简单形式
$ ps
以简略的格式显示当前用户拥有控制终端的进程信息。
2)BSD风格常用选项
$ ps axu
a - 所有用户有控制终端的进程
x - 包括无控制终端的进程
u - 详尽方式显示
w - 增加列宽
3)SVR4风格常用选项
$ ps -efl
-e/-A - 所用用户的进程
-a - 当前终端的进程
-u 用户名/用户ID - 特定用户的进程
-g 组名/组ID - 特定组的进程
-f - 按完整格式显示
-F - 按更完整格式显示
-l - 按长格式显示
4)进程信息列表
USER/UID:进程的实际用户ID
PID:进程ID
%CPU/C:处理器使用率
%MEM:内存使用率
VSZ:占用虚拟内存大小(KB)
RSS:占用半导体内存大小(KB)
TTY:终端机次设备号,“?”表示无控制终端
STAT/S:进程状态
O - 就绪。等待被调度。
R - 运行。正在被处理机执行。 Linux下没有O状态,
处于就绪状态的进程也用R表示。
S - 可唤醒的睡眠。系统中断、获得资源,收到信号,都可被唤醒,
转入运行状态。
D - 不可唤醒的睡眠。只能被wake_up系统调用唤醒。
T - 停止。收到SIGSTOP信号转入停止状态。
收到SIGCONT信号重新转入运行状态。
W - 等待内存分页。2.6版以后的Linux内核以取消此状态。
X - 终止。死亡。不可见。
Z - 僵尸。进程已经终止,但其父进程尚未回收该进程的状态
(尸体)。
< - 高优先级。
N - 低优先级。
L - 存在被锁入内存的分页。实时进程。
s - 会话首进程。
l - 多线程化的进程。
+ - 在前台进程组中的进程。
START/STIME:进程开始时间
COMMAND/CMD:进程启动命令
F:进程标志,1 - 通过fork产生但是没有调用exec。
4 - 拥有超级用户权限。
PPID:父进程的PID。
NI:进程nice值,-20到19,衡量进程对处理器而言的友好程度。
越小越友好。
PRI:进程实际优先级。一个进程的实际优先级由两部分组成:
静态优先级 = 80 + nice,60到99,值越小优先级越高
动态优先级,系统内核可以根据进程表现进行奖惩。
对于处理机消耗型进程,惩罚,降低优先级。
对于I/O消耗型进程,奖励,提升优先级。
ADDR:内核进程的起始地址。普通进程显示“-”。
SZ:虚拟内存页数。
WCHAN:进程正在阻塞的系统调用。
PSR:进程当前正在被哪个处理器执行。
4.父进程、子进程、孤儿进程、僵尸进程
1) 在一个进程中通过特定的系统调用可以创建另一个进程,
创建进程的进程就被成为父进程,被创建的进程被称为子进程。
进程A创建进程B,进程B创建了进程C。
A是B的父进程,B是C的父进程。
C是B的子进程,B是A的子进程。
内核进程(PID=0)
->init进程(PID=1)
->xinetd
->in.telnetd <- 远程用户登录
->login
->bash
->vi
->gcc
->a.out
->...
每个父进程可能会有1到多个子进程,
但是每个子进程只有一个父进程――树状结构。
2)父进程先于子进程结束,子进程就成为孤儿进程,
同时被init进程收养,即成为init进程的子进程。
3)子进程先于父进程结束,但是父进程没有及时回收子进程的状态(尸体),此时该子进程即为僵尸进程。
如果父进程在结束前一直都没有回收子进程的尸体,该尸体就会被init进程回收。
5.进程标识符(PID)
1)系统中的每个进程都以一个唯一的标识号,即PID。
2)任何时刻,不能存在PID相同的进程。进程一旦终止,而且没有成为僵尸,该进程的PID就可以被其它进程复用。
3)延迟重用。
pid_t getpid (void);
获取调用进程的PID。永远不会失败。
二、进程ID相关的函数:getxxxid¶
#include <unistd.h>
getpid - 获取进程标识
getppid - 获取父进程标识
getuid - 获取实际用户ID,即登录shell的用户ID
getgid - 获取实际组ID,即登录shell的组ID
geteuid - 获取有效用户ID
getegid - 获取有效组ID
进程有效用户/组ID默认情况下,取自其实际用户/组ID。
但是,如果该进程所对应的可执行文件带有设置用户/组ID位,
那么该进程的有效用户/组ID,就取自可执行文件的用户/组。
假设a.out文件的用户和组都是root,以tarena用户的身份登录系统,
并执行a.out程序,其运行结果:
实际用户ID:1000
实际组ID:1000
有效用户ID:1000
有效组ID:1000
以root修改a.out文件的权限:
# chmod u+s a.out
# chmod g+s a.out
# ls -l a.out
-rwsr-sr-x 1 root root ... a.out
再次以tarena用户的身份登录系统,并执行a.out程序,其运行结果:
实际用户ID:1000
实际组ID:1000
有效用户ID:0
有效组ID:0
三、fork¶
#include <unistd.h>
pid_t fork (void);
1.创建一个子进程,失败返回-1。
2.调用一次,返回两次。
分别在父子进程中返回子进程的PID和0。
利用该函数返回值的不同,分别父子进程编写处理代码。
3.子进程是父进程的副本,
子进程获得父进程的数据段和堆栈段(包括I/O流缓冲区)的拷贝,
但是父子进程共享同一个代码段。
4.fork函数被调用以后父子进程各自独立地运行,
其被执行的先后顺序无法确定。
某些UNIX实现,会先调度子进程。
5.fork函数被调用以后父进程的文件描述符表,
也会被复制一份给子进程,二者同一个文件表。
6.如果当前线程数已经达到系统的最大线程数,
或者当前用户的进程数已经达到该用户的最大进程数,
那么fork函数会失败。
$ cat /proc/sys/kernel/threads-max
$ ulimit -u
ioctl