💓博主CSDN主页:麻辣韭菜-CSDN博客💓
⏩专栏分类:http://t.csdnimg.cn/G90eI⏪
🚚代码仓库:Linux: Linux日常代码练习🚚
🌹关注我🫵带你学习更多Linux知识
🔝🔝
目录
前言
一阻塞等待和非阻塞等待
替换原理
替换函数
函数解释
命名理解
前言
上篇等待函数里面还有一个参数option参数没有讲,以前演示的fork创建子进程,子进程继承父进程的代码,执行一样的代码,那如果子进程要执行其他的代码怎么办?
一阻塞等待和非阻塞等待
上面的演示可以看出子进程在运行队列里,父进程是没有执行的,被OS放在了等待队列里(也就是阻塞),只有子进程退出的时候,父进程接受到子进程的退出信号,执行waitpid函数进行返回!(父进程是没有退出的)waitpid/wait,可以在目前的情况下,让进程退出具有一定的顺序性!将来可以让父进程进行更多的收尾工作。
从上面阻塞等待来看父进程在子进程运行期间什么事都没有干,那加入我要让父进程干些其他事可以吗? 当然可以。我们先了解下面的参数含义
pid_ t waitpid(pid_t pid, int *status, int options);返回值:当正常返回的时候 waitpid 返回收集到的子进程的进程 ID ;如果设置了选项 WNOHANG, 而调用中 waitpid 发现没有已退出的子进程可收集 , 则返回 0 ;如果调用中出错 , 则返回 -1, 这时 errno 会被设置成相应的值以指示错误所在;参数:pid :Pid=-1, 等待任一个子进程。与 wait 等效。Pid>0. 等待其进程 ID 与 pid 相等的子进程。status:WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)WEXITSTATUS(status): 若 WIFEXITED 非零,提取子进程退出码。(查看进程的退出码)options:WNOHANG: 若 pid 指定的子进程没有结束,则 waitpid() 函数返回 0 ,不予以等待。若正常结束,则返回该子进程的 ID 。
这里的WNOHANG其实也是个宏。运行下面这段代码
等待子进程,父进程完成其他事。
子进程能不能不执行父进程继承下来代码?当然可以请看下面
替换原理
用 fork 创建子进程后,父子进程执行相同的程序 ( 但有可能执行不同的代码分支 ), 子进程往往要调用一种 exec 函数以执行另一个程序。当进程调用一种 exec 函数时 , 该进程的用户空间代码和数据完全被新程序替换 , 从新程序的启动例程开始执行。调用exec 并不创建新进程 , 所以调用 exec 前后该进程的 id 并未改变。
替换函数
我们先来个简单的代码来认识替换函数。这里面6个函数只要掌握了一个其他的也就都会了。
int main()
{printf("当前进程的开始代码!\n");execl("/usr/bin/ls", "ls", "-a", "-l", NULL);exit(1);printf("当前进程的结束代码!\n");return 0;
}
这里补充哈关于第二个 const char* arg 我们在命令行怎么执行命令的,就怎么输,不过是多加了" " 这个而已 。
第二个printf为什么不打印? execl是程序替换函数,调用该函数成功之后,会将当前进程的所有代码和数据都进行替换包括已经执行的和没有执行的! execl调用成功连自己都会被替换掉,所以没有返回值。
函数解释
•这些函数如果调用成功则加载新的程序从启动代码开始执行 , 不再返回。•如果调用出错则返回 -1•所以 exec 函数只有出错的返回值而没有成功的返回值。
命名理解
• l(list) : 表示参数采用列表• v(vector) : 参数用数组• p(path) : 有 p 自动搜索环境变量 PATH• e(env) : 表示自己维护环境变量
excev
int main()
{char *const _argv[NUM] ={(char*)"ls",(char*)"-l",(char*)"-a",NULL};printf("我要开始替换程序了\n");execv("/usr/bin/ls",_argv); exit(1);return 0;}
可以看出execv和上面execl只有传参方式不一样。其他都一样。
execlp
execlp就比execl多个p 而这个p就是传说之中的PATH->(环境变量),想想在Linux中为什么ls可以直接运行不加路径。那是因为ls这个进程继承了bash环境变量。
execle
execle那又是什么? p是系统的,e->(env) :我们自己维护的环境变量。
execvp 和execvpe
这两个,前面看懂了,下去自己可以试试。这里就不演示了。
总结:exec调用带p不用加全路径,带e需要自己组装环境变量。v以数组形式传参,l以列表形式传参。
事实上 , 只有 execve 是真正的系统调用 , 其它五个函数最终都调用 execve, 所以 execve 在 man 手册 第 2 节 , 其它函数在man3手册第3节
下篇综合前面所有知识写一个迷你版的shell 关注我带你学习更多linux知识