IO进程 day04
9. 进程
9.1. 进程和程序的区别
程序:
1. 编译好的可执行的二进制文件
2. 存放在磁盘上,指令和数据的有序集合(文件)
3. 静态的,没有任何执行的概念
进程:
1. 独立的可调度的任务
2. 执行一个程序所分配的资源的总称
3. 进程是程序一次完整执行过程
4. 进程是动态的,包括创建,调度,执行,消亡
5. 进程活动在内存上,断电会丢失
9.2. 进程的特点
- CPU调度进程时会给进程分配时间片(几毫秒~十几毫秒),当进程的时间片用完后,CPU随机调度进程,也可能重复调度同进程,实现进程的轮转,从而实现多任务的操作
- 什么是时间片?
- CPU是怎么调度进程的
- 时间片了解吗
- 系统会为每一个进程分配0-4g的虚拟空间,其中0-3g是每个进程独有的,3-4g是所有进程共有的
9.3. 进程的分段(Linux)
- 正文段:代码段,用于存放被执行的机器指令(通常是只读的)
- 用户数据段:存放进程在执行时直接进行操作的所有数据,包括进程使用的全部变量在内。
- 系统数据段:有效地存放程序运行的环境,包括进程的控制信息等。
9.4. 进程的类型
- 交互进程,由shell控制和运行的。交互进程可以在前台运行,也可以在后台运行。该类进程经常与用户进行交互,需要等待用户的输入,当接收到用户的输入后,该类进程会立即响应。例如:shell命令进程,文本编辑器。
- 批处理进程,该类进程不属于某个终端,被提交到一个队列中顺序执行,例如:数据备份。
- 守护进程,该类进程在后台运行,一般在Linux启动时开始执行,系统关闭时才会结束
9.5. 进程的运行状态
1. 运行态(R):此时正在运行或者准备运行的进程。
2. 睡眠态(等待态):
可中断的睡眠态(S):处于等待状态中的进程,一旦被该进程等待的资源被释放,那么该进程就会进入运行状态。
不可中断的睡眠态(D):该状态的进程只能用wake_up()函数唤醒。
3. 暂停态(T):进程被暂停或者终止
4. 死亡态(X):进程结束
5. 僵尸态(Z):当进程已经终止运行,但还占用系统资源,要避免僵尸态的产生
9.6. 进程的状态转换图
9.7. 进程函数
fork
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
功能:创建一个进程
参数:无
返回值:
成功之后父进程中会返回进程PID,子进程中返回0
失败后父进程会返回-1,更新errno
fork创建子进程的特点
1. fork创建一个子进程,父进程返回子进程的PID,子进程中返回0。
2. fork创建的子进程几乎拷贝了父进程的所有内容,fork之前的代码被复制但不被执行,fork之后的代码复制并执行
3. fork 创建进程一旦成功,进程之间空间相互独立,各自分配0-4g的虚拟内存空间
4. fork创建进程之前打开的文件可以通过复制拿到同一个文件描述符,父子进程可以操作同一个文件(同一个文件指针)
5. 如果父进程退出,子进程没有退出,子进程会变成孤儿进程,被init进程收养,然后孤儿进程变成后台进程
init进程:系统初始化进程,系统启动先创建0号进程,由0号进程创建1号进程,即init进程,0号进程创建完成后,进程退出
僵尸进程:子进程退出,父进程没有及时对子进程的资源进行回收,子进程变成僵尸进程。避免僵尸进程的产生。
fork与vfork
- fork():子进程拷贝父进程的数据段,代码段
vfork():子进程与父进程共享数据段 - fork():父子金策划功能执行次序不确定
vfork():保证子进程先运行,在调用exec()或exit()之前,与父进程数据共享,在exec()或exit()调用之后,父进程才能运行。 - fork: 更通用,适用于需要创建一个完全独立的子进程的场景,vfork: 更适用于子进程立即执行 exec() 覆盖其自身的场景,因为它避免了不必要的地址空间复制,提高了性能。
回收进程资源
wait
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
功能:回收子进程(阻塞)
参数:子进程退出状态,一般为NULL
返回值:
成功:回收的子进程的进程号
失败:返回-1
waitpid
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);
功能:回收子进程资源
参数:
pid:
>0 指定子进程进程号
=-1 任意子进程
=0 等待其组ID等于调用进程的组ID的任一子进程
<-1 等待其组ID等于pid的绝对值的任一子进程
status:子进程退出状态
options:
0:阻塞
WNOHANG:非阻塞
返回值:
正常:结束的子进程的进程号
当使用选项WNOHANG且没有子进程结束时:0
出错:-1
退出进程
exit
#include <stdlib.h>
void exit(int status);
功能:结束进程,刷新缓存
参数:int status:退出的状态
返回值:空
_exit
#include <unistd.h>
void _exit(int status);
功能:结束进程,不能刷新缓存区
参数:int status:可以利用这个参数传递进程结束时的状态。
通常0表示正常结束;
其他的数值表示出现了错误,进程非正常结束
exit和_exit两者区别
exit(0); | _exit(0); | |
---|---|---|
缓存 | 刷新缓存区 | 不会刷新缓存区 |
结束进程 | 关闭所有的打开的文件指针 | 立即终止进程 |
exit和return的区别
exit:结束进程
return:结束函数
exit是函数,return是关键字
获取进程号
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void); // 获取当前进程的进程号
pid_t getppid(void); // 获取当前进程的父进程的进程号
9.8. exec 函数族
作用:在当前进程中执行一个新的进程
头文件
#include <unistd.h>
函数
int execl(const char *path, const char *arg, ...
使用可执行文件的绝对路径或相对路径 path 来替换当前进程的映像。参数通过变长参数列表传递,必须以 NULL 结尾。
int execlp(const char *file, const char *arg, ...
类似 execl,但 file 只需要是可执行文件的名称,函数会根据环境变量 PATH 查找可执行文件的路径。
int execle(const char *path, const char *arg, ...
与 execl 类似,但允许传递一个自定义的环境变量列表 envp。这个环境会代替当前进程的环境变量。
int execv(const char *path, char *const argv[]);
使用路径 path 和参数数组 argv[] 替换当前进程。argv[0] 是程序名,argv[] 数组必须以 NULL 结束。
int execvp(const char *file, char *const argv[]);
类似 execv,但会根据 PATH 环境变量查找可执行文件。
int execvpe(const char *file, char *const argv[],char *const envp[]);
与 execvp 类似,但允许使用自定义的环境变量 envp。