目录
进程终止
进程退出有三种情况
- 代码运行完毕,结果正确
- 代码运行完毕,结果不正确
- 代码异常终止
进程常见退出方法
正常终止(可以通过 echo $? 查看进程退出码)
- 从main返回
- 调用exit
- _exit
异常退出
- ctrl+c,信号终止 kill -9
_exit函数和exit函数的区别
_exit函数
exit函数
这两者之间属于调用与被调用的关系,exit最后也会调用_exit,但在调用_exit之前,还做了其他工作,如下为exit函数的执行流程:
- 执行用户通过atexit或on_exit定义的清理函数
- 关闭所有打开的流,所有的缓存数据均被写入
- 调用_exit
进程等待
什么是进程等待
通过系统调用wait/waitpid,来进行状态检测与回收的功能
为什么需要进程等待?
- 子进程退出,父进程如果不管不顾,可能会造成僵尸进程的问题,僵尸进程无法被杀死,因此只有通过进程等待来杀掉该进程,进而解决内存泄漏问题。
- 我们需要通过进程等待,获得子进程的退出情况(任务完成的怎么样了)。
进程等待的方法
wait方法
如果子进程不退出,父进程默认在wait的时候,调用这个系统调用的时候,也就不返回,默认叫做阻塞状态。
waitpid方法
获取子进程status
wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。
status是一个整数,是32位,我们只考虑它的低16位。
status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特位):
- 正常终止的情况下,低16位的前8位标识进程退出码
- 被信号所杀的情况下,低7位标识终止信号
进程替换
替换函数
其中有六种以exec开头的函数,统称exec函数:
用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序,当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序启动例程开始执行,调用exec并不创建新的进程,所以调用exec前后该进程的id并未改变。
TIPS:
- 程序替换成功之后,exec*后续的代码不会被执行,替换失败,才执行原本后续的代码,exec*函数只有失败返回值,没有成功返回值
- Linux中形成的可执行文件被称为ELF文件,可执行文件的表头指明了程序执行入口地址
- makefile一次要形成多个可执行文件可以引入一个伪目标all,如下:
.PHONY:all
all:otherExe mycommand
otherExe:otherExe.cpp
g++ -o $@ $^ -std=c++11
mycommend:mycommand.c
gcc -o $@ $^ -std=c99
.PHONY:clean
clean:
rm -f otherExe mycommand
环境变量在进行进程替换的时候不会被替换,而是继承下去,父进程所包含的环境变量,子进程会全部继承,子进程新增的环境变量,父进程并不会拥有。