一. int execl( const char *path,const char *arg, ...);
二.int execlp(const char *file,const char *arg, ...);
3、int”execle(const,char,*path,, const. char.*arg, ,... ,char。*const. envp[]);
4、int execv(const char *path, char *const argv[]);
这里要注意,能执行程序替换的函数有很多种,为什么非要用execl呢?,用execlp不是更好吗?(不用加地址)
-
一、进程等待
1.1进程等待的必要性:
解决僵尸进程有三种方法:
1、kill父进程
让子进程变成孤儿进程,被1号程序领养,就解决了问题。
但是这个方法有点怪
2、重启
会重启所以程序,代价会很大
3、进程等待
其中进程等待是最优的解法了,其他两种的代价有点大
1.2、wait 函数(阻塞)
上一个博客有详细解释。
1.3、waitpid函数(可以有非阻塞的功能)
可以看到waitpid函数一共有三个参数。
其有阻塞和非阻塞两种属性:比较重要的是非阻塞属性
接下来就让我们来验证他的非阻塞属性吧:
我们将其的参数设置为WNOHANG,这时候就是非阻塞功能了,
分析可知,假若非阻塞,那么子进程会变成僵尸进程。
结果:
子进程确实变为了僵尸进程,结论成立
那么在非阻塞的前提下,给waitpid函数加上循环的话:
就会一直去进行调用,也可强行实现阻塞功能
小问题:
可以发现,在调用wait和waitpid函数(阻塞情况下)的时候,当子进程还没有退出的时候,父进程好像就只干着这一件事情了,一直在等待着,那么在实际的业务进行的时候,如果是这样的那肯定是不行的,父进程肯定还要做其他更多的事情才行。
怎样解决呢?后续因该会学习,现在先在这里埋个点
二、进程程序替换
2.0、为什么要进行程序替换
因为父进程创建出来的子进程和父进程拥有相同的代码段,如果不进行操作,子进程的功能(代码)不就和父进程一样了吗
当我们想要让子进程执行不同的程序的时候,就需要让子进程调用程序替换的接口,从而让子进程执行不一样的代码
2.1、原理
替换进程都代码段和数据段,更新堆栈
2.2、exec函数簇
(其实这些函数没必要每个都那么认真了解,会用顺手的就行)
一. int execl( const char *path,const char *arg, ...);
参数:
path:带路径的可执行程序(需要路径)
arg:给程序传递命令参数的
1.第一个命令行参数是程序本身
2.最后一个参数以NULL函数结尾(这不就和环境变量一样一样了嘛)
如果需要传递多个参数,则用“,”进行间隔,末尾以NULL结尾
***最后的“ 。。。”表示的是参数列表
返回值:
成功:没有返回值,这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。
可以这么理解:都成功了,那不就直接进行被替换掉程序了,咋可能还有有返回值。
失败:返回-1
~代码实现
替换成 ls
将代码运行起来
可以看到确实是替换成功了。
二.int execlp(const char *file,const char *arg, ...);
可以不带路径是因为以“p”结尾了,会自动使用环境变量PATH去搜索。
代码实现:
可以看到没有带路径也照样实现了ls的功能
3、int”execle(const,char,*path,, const. char.*arg, ,... ,char。*const. envp[]);
4、int execv(const char *path, char *const argv[]);
总结exec函数簇
三、bash的简单模拟,让子进程进行程序替换
3.1原理图
3.2实现
首先肯定得分别创建两个文件:exec_fork_wait和myreplace
让exec_fork_wait创造出来的子进程去替换成为myreolace再去实现功能
myreplace:
如果执行的话就会输出传入的指令 如 -a -b -c
exec_fork_wait:
这里要注意,能执行程序替换的函数有很多种,为什么非要用execl呢?,用execlp不是更好吗?(不用加地址)
因为我们要替换的进程myreplace是自己写的在bash中是没有路径的,不能利用path去找到他的路径,
我们可以通过pwd命令去查找到他的路径
然后在写个makefile文件
这时候要生成两个文件,可以在前面加一个all:【文件一】【文件二】
然后就能一次性生成两个文件
否则make永远只为生成第一个文件而服务,第二个一旦删除就不会再生成了
执行./exec_fork_wait命令
可以看到执行成功(nice)
总结
进程控制二