进程的创建与回收
一、进程的基本概念
1、进程的概念
程序
存放在
磁盘
上的指令和数据的有序集合(文件)
静态
的
进程
执行一个程序所分配的资源的总称
进程是程序的一次执行过程
动态
的,包括创建、调度、执行和消亡
2、进程包含的内容
BSS段
:存放程序中未初始化
的全局变量
数据段
:已初始化
的全局变量
代码段
:程序执行代码
堆(heap)
:malloc等函数分配内存
栈(stack)
:局部变量
,函数参数
,函数的返回值
进程控制块(pcb)
:PID
,进程用户
,进程优先级
,文件描述符表
3、进程的状态
运行态
:进程正在运行
,或者准备运行等待态
:进程在等待一个事件的发生或某种系统资源可中断或
不可中断停止态
:进程被中止
,收到信号后可继续运行死亡态
:已终止
的进程,但pcb没有被释放
4、进程类型
交互进程
:在shell下启动。以在前台
运行,也可以在后台运行批处理进程
:和在终端无关,被提交到一个作业队列
中以便顺序执行守护进程
:和终端无关,一直在后台
运行
二、进程的常用命令
1、查看进程信息
ps
: 查看系统进程快照
top
: 查看进程动态信息
/proc
: 查看进程详细信息
ps 命令详细参数:
-e:显示所有进程
-l:长格式显示更加详细的信息
-f 全部列出,通常和其他选项联用
ps -elf|grep 进程名
:查看与进程名相同
的所有进程的信息
参数的含义:
表头 | 含义 |
---|---|
F | 进程标志,说明进程的权限,常见的标志有两个: 1 :进程可以被复制,但是不能被执行;4 :进程使用超级用户权限 |
S | 进程状态。进程状态。常见的状态有以下几种:1.-D :不可被唤醒的睡眠状态,通常用于 I/O 情况。2.-R :该进程正在运行。3.-S :该进程处于睡眠状态,可被唤醒。4.-T :停止状态,可能是在后台暂停或进程处于除错状态。5.-W :内存交互状态(从 2.6 内核开始无效)。6.-X :死掉的进程(应该不会出现)。7.-Z :僵尸进程。进程已经中止,但是部分程序还在内存当中。8.-< :高优先级(以下状态在 BSD 格式中出现)。9.-N :低优先级。10.-L :被锁入内存。11.-s :包含子进程。12.-l :多线程(小写 L)。13.-+ :位于后台。 |
UID | 运行此进程的用户的 ID |
PID | 进程的 ID |
PPID | 父进程的 ID |
C | 该进程的 CPU 使用率,单位是百分比 |
PRI | 进程的优先级,数值越小,该进程的优先级越高,越早被 CPU 执行 |
NI | 进程的优先级,数值越小,该进程越早被执行 |
ADDR | 该进程在内存的哪个位置 |
SZ | 该进程占用多大内存 |
WCHAN | 该进程是否运行。"-"代表正在运行 |
TTY | 该进程由哪个终端产生 |
TIME | 该进程占用 CPU 的运算时间,注意不是系统时间 |
CMD | 产生此进程的命令名 |
top:
- 查看进程动态信息
shift+>
后翻页shift+<
前翻页
top -p PID
:查看某个进程
2、前后台进程切换
jobs
: 查看后台进程bg
: 将挂起的进程
在后台运行fg
: 把后台运行的进程放到前台运行
ctrl+z
: 把运行的前台进程转为后台并停止。./test &
: 把test程序后台运行
3、改变进程优先级
nice
-按用户指定的优先级运行进程
nice [-n NI值] 命令
- NI 范围是
-20~19
。数值越大
优先级越低
普通用户
调整NI
值的范围是0~19
,而且只能调整自己的进程。普通用户
只能调高
NI
值,而不能降低。如原本 NI 值为 0,则只能调整为大于 0。- 只有
root
用户才能设定进程 NI 值为负值
,而且可以调整任何用户的进程。
renice
-改变正在运行进程的优先级
renice [优先级] PID
三、进程的创建与结束
1、创建子进程
子进程概念
:子进程为由另外一个进程(对应称之为父进程)所创建的进程
创建子进程的函数:
#include <unistd.h>
pid_t fork(void);
创建新的进程,
失败
时返回-1
,成功
时父进程返回子进程的进程号
,子进程
返回0
通过fork的返回值
区分父进程和子进程
要点:
子进程
只执行fork之后的代码
- 父子进程
执行顺序
是操作系统决定
的。
注意:
- 子进程
继承
了父进程的所有内容 - 父子进程有
独立
的地址空间,互不影响
- 若父进程先结束,
子进程
成为孤儿进程
,被init
进程收养,子进程变成后台进程 - 若子进程先结束,父进程如果没有及时回收,
子进程变成僵尸进程
示例:
pid_t pid;
if ((pid = fork()) < 0)
{
perror(“fork”);
return -1;
}
else if (pid == 0)
{
printf(“child process : my pid is %d\n”, getpid());
}
else
{
printf(“parent process : my pid is %d\n”, getpid());
}
2、进程退出
#include <stdlib.h>
#include <unistd.h>
void exit(int status);
void _exit(int status);
结束
当前的进程并将status
返回exit
结束进程时会刷新(流)缓冲区
,_exit
不会
return 和exit的区别
main函数结束时会隐式地调用exit函数,
普通函数return是返回上一级。
示例
#include <stdio.h>
#include <stdlib.h>
int main(void) {
printf(“this process will exit”);
exit(0);
printf(“never be displayed”);
}
./a.out
this process will be exit
四、进程的回收
子进程结束时
由父进程
回收孤儿进程
由init进程
回收- 若没有
及时回收
会出现僵尸进程
1、wait
#include <sys/wait.h>
pid_t wait(int *status);
成功
时返回回收的子进程的进程号
;失败
时返回EOF(-1)
- 若子进程
没有结束
,父进程一直阻塞
- 若有
多个子进程
,哪个先结束就先回收
status
指定保存子进程返回值
和结束方式的地址
status
为NULL
表示直接释放子进程PCB,不接收返回值
示例
int status;
pid_t pid;
if ((pid = fork()) < 0)
{
perror(“fork”);
exit(-1);
}
else if (pid == 0)
{
sleep(1);
exit(2);
}
else {
wait(&status);
printf(“%x\n”, status);
}
2、进程返回值和结束方式
子进程通过exit / _exit / return
返回某个值(0-255)
父进程调用wait(&status)
回收
WIFEXITED(status)
:判断子进程是否正常结束
WEXITSTATUS(status)
:获取子进程返回值
WIFSIGNALED(status)
:判断子进程是否被信号结束
WTERMSIG(status)
:获取结束子进程的信号类型
3、waitpid
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int option);
成功
时返回回收的子进程的pid或0
;失败
时返回EOF(-1)
pid
可用于指定回收
哪个子进程或任意子进程
status
指定用于保存子进程返回值
和结束方式的地址
option
指定回收方式
,0 或 WNOHANG
参数详情:
pid
pid>0
时,只等待进程ID等于pid的子进程
,不管其它已经有多少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。pid=-1
时,等待任何一个子进程
退出,没有任何限制,此时waitpid和wait的作用一模一样。pid=0
时,等待同一个进程组中的任何子进程
,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。pid<-1
时,等待一个指定进程组中的任何子进程
,这个进程组的ID等于pid的绝对值
。
options
- options提供了一些额外的选项来控制waitpid,目前在Linux中只支持
WNOHANG
和WUNTRACED
两个选项,这是两个常数,可以用"|"运算符把它们连接起来使用 WNOHANG
:若由pid指定的子进程未发生状态改变(没有结束),则waitpid()不阻塞
,立即返回0WUNTRACED
: 返回终止子进程信息和因信号停止的子进程信息
wait(wait_stat)
等价于waitpid(-1,wait_stat,0)
到这里就结束啦!