进程管理
一、基本概念
1. 进程与程序
1) 进程就是运行中的程序。
一个运行着的程序,可能有多个进程。进程在操作系统中执行特定的任务。
2) 程序是存储在磁盘上, 包含可执行机器指令和数据的静态实体。
进程或者任务是处于活动状态的计算机程序。
2. 进程的分类
1) 进程一般分为**交互进程**、**批处理进程**和**守护进程**三类。
2) 守护进程总是活跃的,一般是后台运行。
守护进程一般是由系统在开机时通过脚本自动激活启动,
或者由超级用户root来启动。
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: 进程属主。
◦PID: 进程ID。
◦%CPU/C: CPU使用率。
◦%MEM: 内存使用率。
◦VSZ: 占用虚拟内存大小(KB)。
◦RSS: 占用物理内存大小(KB)。
◦TTY: 终端次设备号,“?”表示无控制终端,如后台进程。
◦STAT/S: 进程状态。可取如下值:
◾O - 就绪。等待被调度。
◾R - 运行。Linux下没有O状态,就绪状态也用R表示。
◾S - 可唤醒睡眠。系统中断,获得资源,收到信号,都可被唤醒,转入运行状态。
◾D - 不可唤醒睡眠。只能被wake_up系统调用唤醒。
◾T - 暂停。收到SIGSTOP信号转入暂停状态, 收到SIGCONT信号转入运行状态。
◾W - 等待内存分页(2.6内核以后被废弃)。
◾X - 死亡。不可见。
◾Z - 僵尸。已停止运行,但其父进程尚未获取其状态。
◾< - 高优先级。
◾N - 低优先级。
◾L - 有被锁到内存中的分页。实时进程和定制IO。
◾s - 会话首进程。
◾l - 多线程化的进程。
◾
◾
◾+ - 在前台进程组中。
◦PSR: 进程被绑定到哪个处理器。
-
父进程、子进程、孤儿进程和僵尸进程
- 父进程启动子进程后,子进程在操作系统的调度下与其父进程同时运行。
- 子进程先于父进程结束,子进程向父进程发送SIGCHLD(17)信号,父进程回收子进程的相关资源。
- 父进程先于子进程结束,子进程成为孤儿进程,同时被init进程收养,即成为init进程的子进程。
- 子进程先于父进程结束,但父进程没有回收子进程的相关资源,该子进程即成为僵尸进程。
-
进程标识符(进程ID)
- 每个进程都有一个以非负整数表示的唯一标识,即进程ID/PID。
- 进程ID在任何时刻都是唯一的,但可以重用,当一个进程退出时,其进程ID就可以被其它进程使用。
- 延迟重用。
a.out - 1000
a.out - 1010
a.out - 1020
范例:delay.c
#include <stdio.h>
#include <unistd.h>
int main ()
{
printf ("进程ID:%u\n", getpid ());
return 0;
}
二、getxxxid
#include <unistd.h>
getpid - 获取进程ID
getppid - 获取父进程ID
getuid - 获取实际用户ID
geteuid - 获取有效用户ID
getgid - 获取实际组ID
getegid - 获取有效组ID
范例:id.c
#include <stdio.h>
#include <unistd.h>
int main ()
{
printf (" 进程ID:%u\n", getpid ());
printf (" 父进程ID:%u\n", getppid ());
printf ("实际用户ID:%u\n", getuid ());
printf ("有效用户ID:%u\n", geteuid ());
printf (" 实际组ID:%u\n", getgid ());
printf (" 有效组ID:%u\n", getegid ());
return 0;
}
三、fork
#include <unistd.h>
pid_t fork (void);
- 创建一个子进程,失败返回-1
- 调用一次,返回两次
分别在父子进程中返回子进程的PID和0。
用返回值的不同,可以分别为父子进程编写不同的处理分支。
范例:fork.c
#include <stdio.h>
#include <unistd.h>
int main ()
{
printf ("%u进程:我要调用fork()了...\n", getpid ());
pid_t pid = fork ();
if (pid == -1)
{
perror ("fork");
return -1;
}
if (pid == 0)
{
printf ("%u进程:我是%u进程的子进程。\n", getpid (),
getppid ());
return 0;
}
printf ("%u进程:我是%u进程的父进程。\n", getpid (), pid);
sleep (1);
return 0;
}
- 子进程是父进程的副本
子进程获得父进程数据段和堆栈段(包括I/O流缓冲区)的拷贝,但子进程共享父进程的代码段。
范例:mem.c、os.c、is.c 、mem.c
mem.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int global = 100;
int main ()
{
int local = 200;
char* heap = (char*)malloc (256 * sizeof (char));
sprintf (heap, "ABC");
printf ("父进程:%d %d %s\n", global, local, heap);
pid_t pid = fork ();
if (pid == -1)
{
perror ("fork");
return -1;
}
if (pid == 0)
{
global++;
local++;
sprintf (heap, "XYZ");
printf ("子进程:%d %d %s\n", global, local, heap);
free