目录
续--上一章
1.WIFEXITED && WEXITSTATUS
2.非阻塞等待
进程程序替换
1.先观代码 && 现象
2.原理解释
3.将代码改成多进程版
4.使用所有的替换方法,并且认识函数参数的含义
续--上一章
1.WIFEXITED && WEXITSTATUS
若需要知道退出码的话,还需要对status进行相应的位操作,那那些不懂操作的人该怎么办呢?
第一个 WIFEXITED 返回真时,则代表子进程正常退出,这时的 WEXITSTATUS 返回的就是子进程的退出码:
等待是必须的,但获取子进程的退出信息不是必须的,有时候如果不需要,则int *status输入NULL即可
如果想知道退出信号,就拿位操作去做,一般来说,对于程序员来讲,你只需要关注最终任务完成没有,若是出异常了,那就需要调试了,调试的时候按照自己的动作来调就行了
2.非阻塞等待
如果子进程没有退出,而父进程在进行执行waitpid进行等待时,则会发生阻塞等待 -- 进程阻塞了
即在等待某种条件发生(子进程退出)
在这种阻塞时,父进程其他事情什么都没干
pid_ t waitpid(pid_t pid, int *status, int options);
当options的为 WNOHANG 时,将会进行非阻塞等待
非阻塞等待(本质就是循环检测子进程的状态)就是允许父进程做一些其他的事情
返回值ret
ret > 0 :等待成功了,子进程退出了,并且父进程回收成功
ret < 0 :等待失败了
ret == 0 :检测是成功的,只不过子进程还没退出,需要你下一次进行重复等待
非阻塞等待的时候 + 循环 = 非阻塞轮询
代码测试:
进程程序替换
1.先观代码 && 现象
代码:
现象:
让我们(进程)用exec*(exec系列)的函数,执行起来新的程序
2.原理解释
进程 = 内核数据结构 + 代码和数据
本质上是将当前进程的代码和数据进行替换的一种技术
进程的程序替换并没有创建新的进程!!(该过程并没有把PCB 页表 地址空间 ... 重建)
站在被替换进程的角度:本质就是这个程序被加载到内存了!
怎么加载?exec* 类似于一种Linux上的加载函数
那么对于这个运行结果,为什么下面这条语句未被执行呢?
exec*系列的函数,执行完毕之后,后续的代码不见了,因为被替换了
execl函数的返回值可以不关心了。只要替换成功,就不会向后继续运行,只要继续运行了,一定是替换失败了!
3.将代码改成多进程版
fork创建子进程,让子进程自己去替换
创建子进程,让子进程完成任务:
1. 让子进程执行父进程代码的一部分
2. 让子进程执行一个全新的程序
当 ls指令 在子进程中进行覆盖代码和数据时,也要进行写时拷贝(代码和数据都要)
既然exec* 可以替代系统指令,就也可以替换其他指令已经各种可执行程序
4.使用所有的替换方法,并且认识函数参数的含义
l:list . 列表
path:我们要执行的程序,需要带路径(即怎么找到这个程序,你得告诉我)
后面的参数:在命令行中怎么执行,你就怎么传参
命令行 : $ ls -a -l
execl("/usr/bin/ls", "ls", "-a", "-l", NULL);
参数必须以NULL结尾
V:vector(动态数组)
和execl类似,只不过是将后面的参数放入数组中
P:用户可以不传要执行文件的路径(但是文件名要传),直接告诉exec*,我要执行谁就行
本质就是会在环境变量PATH中进行查找这个名字
e:environment 环境变量
testexec.c:
mypragma.c:
运行:
这就和以前的命令行参数表和环境变量表一样,在父进程中本身会存在这两张表(这里的两张表是我们自定义的),会传递给子进程
但是在父进程本身就会有一批环境变量,从bash来:
即最后一个参数的意义是整体替换所有的环境变量!
1.用全新的给子进程
2.用老的环境变量给子进程, environ3.老的环境变量稍微修改,给子进程(putenv操作可以新增环境变量)