五、进程
10. 进程等待
上一篇我们知道了 wait 和 waitpid 函数都有一个 status 参数,这个参数是什么呢?这个参数其实就是进程的返回结果,当子进程结束的时候,就会返回这个值给父进程。
由上图可知status由三部分组成,其中高16字节不使用,低16字节中的高8字节存储着退出码的信息,低16字节中的第7位字节存储着退出信号的信息。退出信号非0代表程序异常退出,退出码非0代表程序的运行结果不正确。
阻塞等待和非阻塞等待
形参参入 0 是阻塞等待,传入 WNOHANG 是非阻塞等待。阻塞等待就是当父进程没有收到子进程的返回结果时,会在此阻塞,非阻塞等待就是父进程没有收到子进程的返回结果时,仍可以执行其他代码,并不会将父进程阻塞至此。但是需要 轮询操作 来检查子进程是否已经执行完毕。
选择使用阻塞等待还是非阻塞等待取决于具体的应用场景和需求。有些情况下需要保证操作的正确性和顺序性,适合使用阻塞等待;而有些情况下需要提高程序的效率,适合使用非阻塞等待。
11. 进程程序替换
用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支), 子进程往往要调用一种exec函数以执行另一个程序 。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。
有六种以exec开头的函数,统称exec函数:
我们来写一个程序替换的程序。
程序替换一旦成功,exec之后的代码就不再执行。 exec函数只有失败后才会有返回值,成功了没有返回值。替换完成后不会创建新的程序。我们知道,创建一个进程时,先创建的是 PCB,地址空间,页表等,然后再将程序加载到内存,将程序加载到内存与程序替换的本质是一样的。
由于进程具有独立性,子进程替换的时候会发生写实拷贝,所以不影响父进程的代码,父进程同样可以等待子进程的返回结果。
这些函数原型看起来很容易混,但只要掌握了规律就很好记。
l(list) : 表示参数采用列表
v(vector) : 参数用数组
p(path) : 有p自动搜索环境变量PATH
e(env) : 表示自己维护环境变量
进程程序替换,不会替换环境变量数据。
上面的6个函数都是 execve 函数的封装。