进程的创建和回收
进程概念
- 概念
程序
存放在磁盘上的指令和数据的有序集合(文件)
静态的
进程
执行一个程序所分配的资源的总称
动态的 - 进程和程序比较
注:进程是存在RAM中,程序是存放在ROM(flash)中的 - 进程内容
BSS段:存放程序中未初始化的全局变量
数据段:已初始化的全局变量,static声明的变量
代码段:程序执行代码
堆(heap):malloc等函数分配内存
栈(stack):局部变量,函数参数,函数的返回值
进程控制块(pcb):PID, 进程优先级,文件描述符表 - 进程控制块
进程标识PID、进程用户、进程状态、优先级、文件描述符表 - 进程类型
交互进程:在shell下启动,在前台后台运行
批处理进程:和在终端无关,被提交到一个作业队列中以便顺序执行
守护进程:和终端无关,一直在后台运行 - 进程状态
运行态、等待态、停止态、死亡态:
进程常用命令
- 查看进程信息
ps 查看系统进程快照
top 查看进程动态信息
/proc 查看进程详细信息 - 执行命令如下:
ps:当前shell显示
ps -e :所有进程显示
ps -el:是显示详细信息 - 具体命令参数信息如下:
ps 命令详细参数:
-e:显示所有进程
-l:长格式显示更加详细的信息
-f 全部列出,通常和其他选项联用
表头 含义
F 进程标志,说明进程的权限,常见的标志有两个:
1:进程可以被复制,但是不能被执行;
4:进程使用超级用户权限;
S 进程状态。进程状态。常见的状态有以下几种:- -D:不可被唤醒的睡眠状态,通常用于 I/O 情况。
- -R:该进程正在运行。
- -S:该进程处于睡眠状态,可被唤醒。
- -T:停止状态,可能是在后台暂停或进程处于除错状态。
- -W:内存交互状态(从 2.6 内核开始无效)。
- -X:死掉的进程(应该不会出现)。
- -Z:僵尸进程。进程已经中止,但是部分程序还在内存当中。
- -<:高优先级(以下状态在 BSD 格式中出现)。
- -N:低优先级。
- -L:被锁入内存。
- -s:包含子进程。
- -l:多线程(小写 L)。
- -+:位于后台。
UID 运行此进程的用户的 ID;
PID 进程的 ID;
PPID 父进程的 ID;
C 该进程的 CPU 使用率,单位是百分比;
PRI 进程的优先级,数值越小,该进程的优先级越高,越早被 CPU 执行;
NI 进程的优先级,数值越小,该进程越早被执行;
ADDR 该进程在内存的哪个位置;
SZ 该进程占用多大内存;
WCHAN 该进程是否运行。"-"代表正在运行;
TTY 该进程由哪个终端产生;
TIME 该进程占用 CPU 的运算时间,注意不是系统时间;
CMD 产生此进程的命令名;
- 实时查看进程命令如下:
top 查看进程动态信息
shift +> 后翻页
shift +< 前翻页
top -p PID 查看某个进程 - 改变进程优先级
nice 按用户指定的优先级运行进程
nice [-n NI值] 命令
NI 范围是 -20~19。数值越大优先级越低
普通用户调整 NI 值的范围是 0~19,而且只能调整自己的进程。
普通用户只能调高 NI 值,而不能降低。如原本 NI 值为 0,则只能调整为大于 0。
只有 root 用户才能设定进程 NI 值为负值,而且可以调整任何用户的进程。
renice 改变正在运行进程的优先级
renice [优先级] PID - 设置优先级案例如下:
- 改变优先级案例如下:
- 进程相关命令
jobs 查看后台进程
bg 将挂起的进程在后台运行
fg 把后台运行的进程放到前台运行
ctrl + z 把运行的前台进程转为后台并停止 - 案例代码如下:
编写一个.c文件,然后调用一个简单的sleep函数后,执行test后在另一个端口查看进程如下:
注:上述是在运行函数后,按ctrl + Z使其进程进入停止状态T
创建子进程
- 子进程概念
子进程为由另一个进程(对应称之为父进程)所创建的进程,实际上你在linux中写程序都是别人创建的,比如运行.test文件时,就是shell的子进程 - 子进程创建-fork
#include <unistd.h>
pid_t fork(void);
创建新的进程,失败时返回-1
成功时父进程返回子进程的进程号,子进程返回0
通过fork的返回值区分父进程和子进程 - 创建子进程案例如下:
注:创建子进程时虽然会复制父进程的代码,但是不会从头开始执行,而是从创建fork函数下方的时候执行,所以子进程没有赋予相应的进程号,但是系统默认给了0,下面图片显示得很清楚
要点:1 子进程只执行fork之后的代码
父子进程执行顺序是操作系统决定的。 - 父子进程
子进程继承了父进程的内容
父子进程有独立的地址空间,互不影响
若父进程先结束
子进程成为孤儿进程,被init进程收养
子进程变成后台进程
若子进程先结束
父进程如果没有及时回收,子进程变成僵尸进程 - 父子进程案例如下:
- 运行如下:
注:可以得出父子进程没有什么特定的关系,是系统随机调用的 - 通过父进程号看出子进程和父进程
- 在用kill -9 杀死父进程,然后可以发现子进程的父进程PPID变成1,也就是init进程中,然后另一个终端ctrl + c结束不掉,说明以及变为后台进程了
注:有些新版的ubuntu系统子进程可能被其他进程领养,例如:systemd作为最新的初始化系统(init)来提高系统的启动速度。这和进程1的init是一个道理不要疑惑。
子进程进阶例题
- 一个父进程拥有五个子进程,代码如下:
- 运行结果如下:
注:可以看出出现了孙进程的情形,因为上述代码中for循环语句,使子进程执行完fork函数下面的语句后,由于for内部是一个循环语句,因此子进程也执行了一次fork函数所以出现孙进程的情形 - 解决办法如下:
注:在子进程语句中末尾加入break即可