Operating Systems: Three Easy Pieces(操作系统:三个简单方面)5进程API/5.2&&5.3wait()和exec()
2016-07-12 13:59
393 查看
5.2系统调用wait()
迄今为止,我们还没做多少工作,只是创建了一个子进程打印了点信息就退出了。事实说明,有时候让父进程去等待子进程结束是十分有用的。这项工作就是由wait()函数完成的(或者由waitpid()函数完成)详见figure5.2。
在程序p2.c中,父进程通过调用wait()函数来延迟自身的执行直至子进程执行完成。当子进程完成,wait()函数就返回到父进程中。
在上面的程序中加入wait()函数使得程序的输出变得确定。你知道为什么咩?小小滴思考一下~
(进入wait过程等待您的思考……考虑完毕,进程结束)
现在你应该已经想了一会了,这里给大家展示一下程序输出:
因此,即使是父进程先执行,它也会礼貌的等待子进程结束后,wait()函数返回后再打印自己的输出信息。
5.3系统调用exec()函数族
最后一个重要的进程创建的API是exec()。在你想要运行一个程序而非调用程序时,这个系统调用非常适用。比如,在程序p2.c中调用fork()函数只是对你在程序运行时拷贝一个与父进程一样的进程有用。然而,我们更多的是想要运行一个不同的程序,exec()函数就是帮我们完成这项工作的。
Figure 5.3: 调用 fork(), wait(), 和 exec()函数 (p3.c)
在例子5.3中,子进程调用了execvp()来运行进程统计对象wc。实际p3.c源文件运行wc来统计告知我们文件有多少行,多少单词和字节。
这里的fork()函数很奇怪,同样exec()函数也不正常。它做的事情是:在给了执行对象(wc)和参数(p3.c)的情况下,载入可执行程序中的代码并用来覆盖当前的代码段,内存空间的堆栈以及其他部分都重新初始化。然后操作系统开始执行这个程序,并按照argv那样传递进程的参数。因此,它并没有创建一个新的进程,实际上,他只是将当前运行的进程(p3)转换到另一个不同的运行中的进程(wc).当子进程的exec()函数执行完成后,整个程序看起来好像p3从没运行过。一个成功的exec()调用从来不会返回。
迄今为止,我们还没做多少工作,只是创建了一个子进程打印了点信息就退出了。事实说明,有时候让父进程去等待子进程结束是十分有用的。这项工作就是由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()调用从来不会返回。
相关文章推荐
- 本地yum源搭建及failed to retrieve解决
- 图解RAID 0, RAID 1, RAID 5, RAID 10
- 实用的Portraiture滤镜磨皮教程
- 域名查询工具 Domain Serach
- Codeforces C2. Brain Network (medium)
- Andriod Studio adb.exe,start-server' failed -- run manually if necessary 解决
- Codeforces C1. Brain Network (easy)
- 【bzoj2434-阿狸的打字机】AC自动机+fail树+优化
- hdu 4300 Clairewd’s message
- email 发送邮箱修改密码
- linker command failed with exit code 1 (use -v to see invocation)
- 【打CF,学算法——二星级】Codeforces 22B Bargaining Table(区域和)
- Installation error: INSTALL_FAILED_UPDATE_INCOMPATIBLE解决方法
- [Cloud Computing]Mechanisms: Failover System
- saiku2.x刷新缓存的方法
- Mybaits深入了解(三)----mybatis开发Dao的方法
- 自定义Canvas
- paint Canvas画笔、画布
- Web QQ API 分析
- HDU2057 A + B Again