接下来一个脱口而出的疑问是:好不容易生了个孩子,但是干的事情跟父进程是一样的, 那我们要这个孩子有何用呢?答案是:上述代码确实没有什么实际意义,事实上我们一般会 让孩子去执行一个预先准备好的 ELF 文件或者脚本,用以覆盖从父进程复制过来的代码, 先来介绍这个加载 ELF 文件或者脚本的接口函数:
功能
在进程中加载新的程序文件或者脚本,覆盖原有代码,重新运行
头文件
#include
原型
int execl(const char *path, const char *arg, ...);
int execv(const char *path, char *const argv[ ]);
int execle(const char *path, const char *arg, ..., char * const envp[ ]);
int execlp(const char *file, const char *arg, ...);
int execvp(const char *file, char *const argv[ ]);
int execvpe(const char *file, char *const argv[ ],char *const envp[ ]);
参数
path
即将被加载执行的 ELF 文件或脚本的路径
file
即将被加载执行的 ELF 文件或脚本的名字
arg
以列表方式罗列的 ELF 文件或脚本的参数
argv
以数组方式组织的 ELF 文件或脚本的参数
envp
用户自定义的环境变量数组
返回值
成功
不返回
失败
- 1
备注
1,函数名带字母 l 意味着其参数以列表 (list) 的方式提供。
2,函数名带字母 v 意味着其参数以矢量 (vector ) 数组的方式提供。
3,函数名带字母 p 意味着会利用环境变量 PATH 来找寻指定的执行文件。
4,函数名带字母 e 意味着用户提供自定义的环境变量。
表 函数族 exec( )的接口规范
使用exec函数注意事项
1,被加载的文件的参数列表必须以自身名字为开始,以 NULL 为结尾。比如要加载执 行当前目录下的一个叫做 a.out 的文件,需要一个参数”abcd”,那么正确的调用应该是:
execl(“ ./a.out”, “a.out”, “abcd”, NULL);
或者:
const char *argv[3] = {“a.out”, “abcd”, NULL};
execv(“ ./a.out”, argv);
2,exec 函数簇成功执行后,原有的程序代码都将被指定的文件或脚本覆盖,因此这些 函数一旦成功后面的代码是无法执行的,他们也是无法返回的。
示列代码如下:
#include
#include
#include
#include
#include
int main()
{
printf("hello\n");
pid_t pid = fork();
if(pid == 0)
{
execl("./son","./son","1.txt","2.txt","3.txt",NULL);//函数名带l 参数以列表的方式提供
//定义参数数组
// char *arg[] = {"./a.out","1.txt","2.txt","3.txt",NULL};
// execv("./a.out",arg);//函数名带v,将参数列表以数组的方式传入
//execl("/bin/ls","ls",NULL);//execl也可以直接使用shell命令替换子进程的代码,但是需要指定shell命令的路径
//execlp("ls","ls",NULL);//函数名带p,自动寻找环境变量,不需要指定路径
printf("[我是son]world,[自己的pid]%d,[父进程的pid]%d\n",getpid(),getppid());
//getpid(),getppid()
//给出一个退出值
exit(99);//exit可以自己指定退出值
}
if(pid > 0)
{
//wait(),等待子进程
int status;
wait(&status);
printf("[我嫩爹]world,[自己的pid]%d,[父进程的pid]%d\n",getpid(),getppid());//
printf("[退出状态值]%d\n",WEXITSTATUS(status));
//status是一个4个字节的状态值,其中最后一个字节才是退出值,用宏WEXITSTATUS()可以直接打印退出值
}
return 0;
}
上述代码注释部分解释了exec的多种用法!
上述程序中使用wait函数如下
功能
等待子进程
头文件
#include
原型
pid_t wait(int *stat_loc);
pid_t waitpid(pid_t pid, int *stat_loc, int options);
参数
pid
小于-1 :等待组 ID 的绝对值为 pid 的进程组中的任一子进程
-1:等待任一子进程
0:等待调用者所在进程组中的任一子进程
大于 0 :等待进程组 ID 为 pid 的子进程
stat_loc
子进程退出状态
option
WCONTINUED:报告任一从暂停态出来且从未报告过的子进程的状态
WNOHANG:非阻塞等待
WUNTRACED:报告任一当前处于暂停态且从未报告过的子进程的状态
返回值
wait( )
成功:退出的子进程 PID
失败:- 1
waitpid( )
成功:状态发生改变的子进程 PID (如果 WNOHANG 被设置,且由 pid 指 定的进程存在但状态尚未发生改变,则返回0) 。
失败:- 1
备注
如果不需要获取子进程的退出状态,stat_loc 可以设置为 NULL
表 5-4 函数 wait()和 waitpid()的接口规范
注意,所谓的退出状态不是退出值,退出状态包括了退出值。如果使用以上两个函数成 功获取了子进程的退出状态,则可以使用以下宏来进一步解析:
宏
含义
①
WIFEXITED(status)
如果子进程正常退出,则该宏为真。
WEXITSTATUS(status)
如果子进程正常退出,则该宏将获取子进程的退出值。
WIFSIGNALED(status)
如果子进程被信号杀死,则该宏为真。
WTERMSIG(status)
如果子进程被信号杀死,则该宏将获取导致他死亡的信号值。
② WCOREDUMP(status)
如果子进程被信号杀死且生成核心转储文件 (core dump) , 则该宏为真。
WIFSTOPPED(status)
如果子进程的被信号暂停,且 option 中 WUNTRACED 已经被 设置时,则该宏为真。
WSTOPSIG(status)
如果 WIFSTOPPED(status)为真,则该宏将获取导致子进程暂 停的信号值。
WIFCONTINUED(status)
如果子进程被信号 SIGCONT 重新置为就绪态,该宏为真。
表 5-5 处理子进程退出状态值的宏
①正常退出指的是调用 exit( )/_exit( ),或者在主函数中调用 return,或者在最后一个 线程调用 pthread_exit( )。
②由于没有在 POSXI.1-2001 标准中定义,这个选项在某些 Unix 系统中无效,比如 AIX, 或者 sunOS 中。