5.2系统调用wait()
迄今为止,我们还没做多少工作,只是创建了一个子进程打印了点信息就退出了。事实说明,有时候让父进程去等待子进程结束是十分有用的。这项工作就是由wait()函数完成的(或者由waitpid()函数完成)详见figure5.2。
在程序p2.c中,父进程通过调用wait()函数来延迟自身的执行直至子进程执行完成。当子进程完成,wait()函数就返回到父进程中。
在上面的程序中加入wait()函数使得程序的输出变得确定。你知道为什么咩?小小滴思考一下~
(进入wait过程等待您的思考……考虑完毕,进程结束)
现在你应该已经想了一会了,这里给大家展示一下程序输出:
prompt> ./p2
hello world(pid:29266)
hello, I am child(pid:29267)
hello, I am parentof 29267 (wc:29267) (pid:29266)
prompt>
根据这些代码,我们现在可以知道,子进程永远在父进程前面执行输出操作。为什么我们会知道咧?首先,可能子进程先执行了所以在父进程之前打印。然而,也可能碰巧父进程先运行,那么他会立即出发wait()函数从而让子进程开始执行直至子进程结束退出,然后才会返回到父进程中继续执行。
因此,即使是父进程先执行,它也会礼貌的等待子进程结束后,wait()函数返回后再打印自己的输出信息。
5.3系统调用exec()函数族
最后一个重要的进程创建的API是exec()。在你想要运行一个程序而非调用程序时,这个系统调用非常适用。比如,在程序p2.c中调用fork()函数只是对你在程序运行时拷贝一个与父进程一样的进程有用。然而,我们更多的是想要运行一个不同的程序,exec()函数就是帮我们完成这项工作的。
#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
printf("hello world (pid:%d)\n",(int) getpid());
int rc = fork();
if (rc < 0) { // fork failed; exit
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) { // child (new process)
printf("hello, I am child(pid:%d)\n", (int) getpid());
char *myargs[3];
myargs[0] = strdup("wc"); //program: "wc" (word count)
myargs[1] = strdup("p3.c"); //argument: file to count
myargs[2] = NULL; // marks end of array
execvp(myargs[0], myargs); // runs word count
printf("this shouldn’t print out");
} else { // parent goes down this path (main)
int wc = wait(NULL);
printf("hello, I am parent of %d (wc:%d)(pid:%d)\n",
rc, wc, (int) getpid());
}
return 0;
}
Figure 5.3: 调用 fork(), wait(), 和 exec()函数 (p3.c)
在例子5.3中,子进程调用了execvp()来运行进程统计对象wc。实际p3.c源文件运行wc来统计告知我们文件有多少行,多少单词和字节。
prompt> ./p3
hello world(pid:29383)
hello, I am child(pid:29384)
29 107 1030 p3.c
hello, I am parentof 29384 (wc:29384) (pid:29383)
prompt>
这里的fork()函数很奇怪,同样exec()函数也不正常。它做的事情是:在给了执行对象(wc)和参数(p3.c)的情况下,载入可执行程序中的代码并用来覆盖当前的代码段,内存空间的堆栈以及其他部分都重新初始化。然后操作系统开始执行这个程序,并按照argv那样传递进程的参数。因此,它并没有创建一个新的进程,实际上,他只是将当前运行的进程(p3)转换到另一个不同的运行中的进程(wc).当子进程的exec()函数执行完成后,整个程序看起来好像p3从没运行过。一个成功的exec()调用从来不会返回。