linux ---- 进程 --- 2

本文详细介绍了exec函数族在进程控制中的作用及其多种实现形式,并对比了它们之间的差异。此外,还探讨了wait和waitpid函数如何用于父进程获取并处理子进程的终止状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2> exec函数
  fork函数创建子进程后,执行的是和父进程相同的程序,子进程往往要调用exec来执行另一个程序,当进程调用exec函数时, 该进程的用户空间代码以及数据完全被替换掉,从新的程序启动例程开始执行。调用exec并不创建新的进程,所以调用exec进程的ID没有改变。

exec函数是有六种,分别如下:
#include <unistd.h>
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ...,char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);

以上这些函数如果执行成功,则加载新的程序,从启动代码开始执行,并且不再返回,如果调用出错了,就返回-1.

这些函数看起来很容易混淆,其实只要掌握规律来记,也是很简单的。
不带自己字母p(p 表示PATH), 第一个参数必须是程序的相对路径或者绝对路径。
带p的, 如果参数中包含‘/’, 则将其视为路径名, 否则为不带路径的程序名,在PATH中搜索这个程序。
带l(表示list)的,要求将新程序的每一个命令行参数都当作一个参数传给它。命令行参数的个数是可变的,因此原型中有...,...中的最后一个可变参数应该为NULL,起sentinel的作用。
带v(vector)的,  则应该先构造一个指向个参数的指针的数组,然后将该数组的首地址传给它, 数组中的最后一个参数也应该是NULL, 就像main函数的argv一样。
带e(environment), 可以把一个新的环境变量表传给他,其他的exec函数都是使用当前的环境变量表。

exec调用举例如下;
---------------------------------------------------------------------------------
char *const ps_argv[] ={"ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL};
char *const ps_envp[] ={"PATH=/bin:/usr/bin", "TERM=console", NULL};
execl("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);
execv("/bin/ps", ps_argv);
execle("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL, ps_envp);
execve("/bin/ps", ps_argv, ps_envp);
execlp("ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);
execvp("ps", ps_argv);

exec函数之间的关系如下:
linux <wbr>---- <wbr>进程 <wbr> <wbr>--- <wbr>2

注意:
exec调用后,原来打开的文件描述符,还是打开的, 这个特性可以用来实现I/O的重定向。



3. wait/ waitpid
一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存, 但它的PCB还保留着,内核在其中保存了一些信息:如果是正常退出,则保存着退出状态, 如果是异常终止,则保存着导致系统进程终止的信号。
如果一个进程已经终止,但是他的父进程未调用wait/waitpid来对它进行清理,这时的进程状态称为僵尸状态,任何进程在终止后,都是僵尸状态。正常情况下,父进程会在子进程终止后,立即清理它的。

Kill命令是无法杀死僵尸进程的,因为kill命令是用来终止进程的,而僵尸进程是已经终止了的。

wait/waitpid函数的原型如下:
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
若调用成功则返回被清理的子进程的PID, 否则返回-1.

父进程调用wait/waitpid可能会有如下情况:
  • 阻塞
  • 带子进程的终止信息立即返回
  • 带错立即返回
这两个函数的差异:
  • 如果父进程的所有子进程都还在运行,调用wait, 将使父进程阻塞, 而调用waitpid时,可以在option中指定WHNOHANG, 使父进程不阻塞而立即返回0.
  • wait等待第一个返回的子进程,而waitpid可以等待指定的进程
可以wait/waitpid不仅可以获得终止信息,而且可以使父进程阻塞,等待子进程终止,起到进程间同步的作用。如果参数status不为空,则子进程的终止信息将通过这个指针返回。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值