文章目录
- 1.`fork`函数
- 2.进程退出码
- 2.1什么是退出码
- 2.2查看程序的退出码
- 2.3退出码的设置
- 1.`exit`函数
- 2.`_exit`函数
- 3.进程等待
- 3.1为什么进程要有进程等待
- 3.2进程等待的方法
- 1.`wait`函数
- 2.`waitpid`函数
- 4.进程替换
- 1.`execl`函数
- 2.`execlp`函数
- 3.`execv`函数
- 4.`execvp`函数
- 5.`execvpe`函数
- 5.1`putenv`函数
- 5.2`environ`函数辅助
- 6.`.execve`系统调用
1.fork
函数
这个函数的使用我们之前已经使用过了,就不在赘述了
重点是:当子进程要更改数据的时候操作系统如何判断从而进行写时拷贝呢?
我们之前说页表有有权限判断的操作,那么如果子进程要修改数据是无权限,就会引发错误,通过判断是否引发错误从而判断是否要写时拷贝
这样就可以减少内存浪费同时也减少创建子进程的成本
2.进程退出码
2.1什么是退出码
我们都知道C/C++程序在退出的时候都有返回值
若为0就代表代码运行完成结果正确
非0就代表代码运行完成结果不准确
而还有一种情况代表代码一次终止
但是程序都有返回值来让我们知道程序的情况
常见的退出码如下:
2.2查看程序的退出码
直接使用echo $?
就可以打印上次程序的退出码了
这里第二次的退出码是0指的是上一个echo $? ,而不是我们自己的程序
我们又发现如果一个程序正常运行且结果正确,可以返回我们输入的返回值
但是如果程序运行不正确就无法返回我们输入的值,而是直接返回错误对应的值
2.3退出码的设置
1.exit
函数
头文件<stdlib.h>
,是一个库函数
和return
被区别是被调用即使在函数中也会强制退出
2._exit
函数
_exit
属于系统调用,头文件为<unistd.h>
是属于系统调用
和exit
库函数的区别如下
exit | _exit |
---|---|
库函数 | 系统调用 |
进程退出的时候会刷新缓冲区 | 进程退出的时候不会刷新缓冲区 |
由此也可以得到: 缓冲区一定不是操作系统的东西,而是库缓冲区,是由C语言提供的缓冲区
3.进程等待
3.1为什么进程要有进程等待
之前讲过,子进程退出,父进程如果不管不顾,就可能造成“僵尸进程”的问题,进而造成内存泄漏。
另外,进程一旦变成僵尸状态,那就刀枪不入,“杀人不眨眼”的 kill -9
也无能为力,因为谁也没有办法杀死一个已经死去的进程。
最后,父进程派给子进程的任务完成的如何,我们需要知道。如,子进程运行完成,结果对还是不对,或者是否正常退出。
父进程通过进程等待的方式:回收子进程资源(重要),获取子进程退出信息(可选)。
3.2进程等待的方法
1.wait
函数
2.waitpid
函数
第一个参数:
先不管后面的参数直接进行使用:
第二个参数:
使用需要定义一个status
在waitpid中传入&status
就可以拿到进程的退出码
为什么status是256呢?
在我们的status
是int类型有32个比特位
其中高16位我们不考虑
而底16位前8位为退出状态(退出码),后7位为终止信号,中间的一位是core dump
占一个标志位,如果进程正常core dump
也是0
我们的退出信号后有8位也就是2^8
所以我们想要得到退出码就要先将status>>8
后将中间的数组取出来然后(status>>8) & 0xFF
**(0xFF = 11111111 二进制,8位全1)**就可以拿到了
在输出的时候可以向上图一样用(status>>8)&0xFF
也可用系统提供的宏定义WEXITSTATUS(status)
也可以拿到
异常信号
当程序为异常退出那么退出码就无意义,当代码异常(如:1,2,3)代表代码没有运行完直接就退出了
用status&0x7F
(0x7F = 01111111)就可以拿到进程的退出信号了
第三个参数:
阻塞等待: 指父进程在等子进程的时候不运行,仅仅等待他
非阻塞等待:指父进程在等待子进程的时候也运行自己的代码提升效率
第三个参数传0就代表阻塞等待,传WNOHANG
就是非阻塞等待
让父进程执行其他任务:
运行结果如下:
4.进程替换
1.execl
函数
execl
的第一个参数需要传入的是我们要替换程序的路径
第二个参数我们在shell中怎么写这里就这么写
最后以NULL
结尾就完成了execl的调用
使用效果如下:
当进程完成了替换,后续的代码也就不在执行了:
当然替换的程序可以使任何在Linux中可以执行的代码:
那么有个问题:进程替换后续代码不在执行那么会创建新的进程吗?
通过代码就可以发现进程的替换并不会创建新的进程,而是直接用当前的进程直接去执行
2.execlp
函数
和execl
函数不同的是execlp
函数无需指定程序的路径,直接在系统文件中查找
当让也可以指定路径和execl
的用法一样
3.execv
函数
这里的v
代表的是vector
指的是要替换的程序可以用字符串数组的方式进行传入:
4.execvp
函数
这个函数的第一个参数可以使用字符串数组中的第一个参数进行传参
5.execvpe
函数
这个函数可以让我们的进程向替换的进程中传入一张我们设置的环境变量表
但是这样做之后就无法将系统的环境变量表传入到我们替换的程序中了
5.1putenv
函数
这个函数可以将我们设置的环境变量表新增到我们系统传入给进程的环境变量的后面
5.2environ
函数辅助
当然如果非要直接传入我们可以使用environ
函数获取环境表量表后,再给子进程
6..execve
系统调用
我们的在上层使用的函数都调用了我们.execve
这个系统调用来实现的
这也是我们为什么不用再上面所有函数中传入环境变量就以自动去获取的原因