目录
1. 进程创建
1.1 . / 可执行程序创建进程
通过运行可执行程序可以产生进程
1.2 fork函数创建进程
fork函数会在已存在的进程中再创建出一个子进程,而原进程就为父进程
调用fork函数,OS会作出什么呢?
- 分配新的内存块和内核数据给子进程
- 将父进程的部分数据结构拷贝给子进程
- 将子进程添加到运行队列
- fork返回,开始调度
1.2.1 fork的返回值
如果成功,给父进程返回子进程的pid,给子进程返回0,如果不成功,给子进程返回-1
1.3 写时拷贝
调用fork函数,父子进程在只读的情况下共有同一套代码,但一旦有进程发生修改,则就会发生写时拷贝来维护进程的独立性。
2. 进程结束
2.1 进程结束的三种场景
- 代码运行完毕,结果正确
- 代码运行完毕,结果不正确
- 代码运行失败
2.2 进程结束的退出方法
正常退出:
- 从main函数中退出
- 调用exit函数
- 调用_exit函数
异常退出:
ctrl + c
2.3 exit函数和_exit函数的区别
首先我们来看一段代码:
我们发现当使用_exit退出进程时,没有打印任何信息,这是因为_exit退出进程时,不会刷新缓冲区,而exit在退出时,会刷新缓冲区。
3. 进程等待
3.1 进程等待的必要性
- 之前我们谈及到僵尸进程,即如果子进程退出,且父进程不管不顾就会变成僵尸进程
- 一旦一个进程变成了僵尸进程,那么该进程就会"刀枪不入",无论使用什么都杀不死该进程,因为无法杀死一个已经死去的进程
- 而僵尸进程的最大危害就是:造成内存泄漏
- 父进程可以通过等待的方式,回收到子进程的退出信息,从来解决僵尸进程
3.2 进程等待的方法
1. wait方法
2. waitpid方法
pid_ t waitpid(pid_t pid, int *status, int options);
返回值:
当正常返回的时候waitpid返回收集到的子进程的进程ID;
如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
参数:
pid:
pid=-1,等待任一个子进程。与wait等效。
pid>0.等待其进程ID与pid相等的子进程。
status:
WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常 退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)
options:
WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID
wait相当于waitpid(-1,&status,0)
在等待期间又分为两种等待方法:
1. 阻塞等待(没有添加WNOHANG)
如果子进程已经退出,则waitpid立即返回,如果没有退出则等待进程直到子进程退出,不会进行下一个语句
2. 非阻塞等待
如果子进程已经退出,则waitpid立即返回,如果没有退出则返回0,不进行等待,直接进行下一个语句,若正常等待则返回该子进程的pid
3.3 获取子进程的status
- wait和waitpid都有一个输出性参数status,由操作系统来填充
- 如果传入参数是NULL,则说明不关心进程的退出状态信息
- 需要将status当做位图来看
status后16位中的[9-16]位就是子进程的退出码,前7位是子进程非正常退出时的退出信号
如何获取退出码?
1. WEXITSTATUS(status)来获取正常退出的退出码
2. (status)>> 8 & 0xff
如何获取退出信号 : status >> 0x7f
4. 进程替换
4.1 为什么要有进程替换?
用fork创建出的子进程执行的是和父进程相同的代码,而如果我们需要子进程执行不同的代码,那么就需要调用exec函数来完成进程替换
4.2 替换原理
当进程调用exec函数时,该进程的代码和数据被新的进程替换,从新程序开始运行,但是没有产生新的进程,仍然使用的原进程的pcb
4.3 替换函数
Linux中替换的函数分为6种:
函数返回值:
如果失败会返回-1
函数名称解释:
- l (list) :传入的参数是以列表方式
- v (vector) :传入的参数是以数组方式
- p (path) :存在path环境变量来自动寻找
- e (env) : 使用自己的环境变量