免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 26507 | 回复: 72
打印 上一主题 下一主题

[函数] 大家不觉得fork和exec函数很奇怪吗? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-06-16 16:11 |只看该作者 |倒序浏览
小弟最近刚开始研究unix编程,看的是《unix环境高级编程》这本书,疑问很多,在此先请教一个问题:

书上说除了init进程以外,unix创建进程唯一的办法就是使用fork系统调用。
那么我的疑问是:unix为什么要以fork的方式创建进程?为什么这样设计?

书上说fork有两个作用:1。执行代码分支;2. 用exec调用新的程序;

1. 执行代码分支的确很方便,但是为了一个很小的分支复制整个父进程,我感觉这样很不聪明。

2. 用exec调用其他程序就更麻烦了。
fork要先把父进程复制一份内存空间(虽然有写时复制技术可以优化这点,但是还是很麻烦),并产生了新的进程id,然后exec在子进程空间中运行,载入目标程序的正文段代码和其他内存分配,这样就把刚才fork后产生的主进程内存空间副本覆盖掉了。然后目标程序执行完毕退出。内核将信号通知给父进程。
由于目标程序的代码已经被载入并覆盖到进程空间,那么有个矛盾:
exec函数后面的代码还执行吗?
(1)如果执行,那么由于fork产生的内存空间已经被覆盖掉了,正文段又要重新载入吗?
(2)如果不执行,那么exec的返回值怎么处理?if(execlp("./sub", sub_arg, NULL) < 0)的比较语句如何执行?

创建一个新进程需要如此捣腾,绕的弯路也太大了吧,为什么后来没有采用CreateProcess这种简单调用的方式呢?

后面是我写的代码,经过我的测试。exec函数执行成功后的代码不会执行了,是我的测试代码有错吗?

当然,官方的fork和exec系列函数解释非常滴水不露,fork产生新进程,复制进程空间,exec重新载入了新的程序文件,这样目的是达到了,exec后面的代码不执行也是合理的。但是unix为什么采用这么别扭的设计?
也许在unix产生的年代,结构化的思想还不是很受重视,导致这样的设计一直延续?而unix太伟大了后人一直没有超越当年的前辈,从而不敢逾越?


  1. 。。。。。
  2. int main(int argc, char * argv[], char * envp[])
  3. {
  4.     pid_t cpid;
  5.     char sub_arg[256] = "-l";

  6.     if(cpid = fork() == 0)
  7.     {
  8.         ////注意这里,if是需要execlp函数返回的,if编译后的比较语句应该在execlp返回后执行
  9.         if(execlp("./sub", sub_arg, NULL) < 0)   
  10.             perror("execlp error");

  11.         //经过我测试,这段代码没有执行,没有输出,也没有写文件
  12.         if(-1 == printf("\n exec end \n"))
  13.         {//记录日志,防止printf由于标准输出可能已经被关闭导致的失败
  14.            FILE *fp = fopen("log", "w+");
  15.            if(fp==NULL){
  16.                perror("log error");
  17.                exit(0);
  18.            }
  19.            fputs("run log", fp);
  20.            fclose(fp);
  21.         }
  22.     }
  23.     else
  24.     {
  25.         int i=0;
  26.         wait(&i);
  27.         printf("main end\n");
  28.     }
  29. }

复制代码


下面是另一段测试代码,说明exec系列函数语义如此特别,导致这样的代码不能执行:

  1. int main(int argc, char * argv[], char * envp[])
  2. {
  3.     char sub_arg[256] = "-l";

  4.     if(execlp("ls", sub_arg, NULL) < 0)
  5.          perror("execlp error");

  6.     //下面的代码不会执行了, 我们会看到程序仅仅输出了一次 ls -l 的结果

  7.     if(execlp("ls", sub_arg, NULL) < 0)
  8.          perror("execlp error");

  9.     if(execlp("ls", sub_arg, NULL) < 0)
  10.          perror("execlp error");

  11. }
复制代码

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
2 [报告]
发表于 2006-06-16 16:19 |只看该作者
〉〉exec函数后面的代码还执行吗?
你看书都不仔细,还写代码来验证。
哎。

论坛徽章:
0
3 [报告]
发表于 2006-06-16 16:21 |只看该作者
CreateProcess 简单吗?


那是你没有进行复杂的进程创建。等你用到了,就会发现这个函数后面要跟着一大串的参数...

论坛徽章:
0
4 [报告]
发表于 2006-06-16 16:26 |只看该作者
to 2楼:
如果不执行,那么if如何得到exec的返回值??

to 3楼:
我是说实现起来CreateProcess更简单。而不是程序员调用简单。实现时, 比先fork复制一块内存,然后exec再载入覆盖这块内存,再加个写时复制技术进行优化。。进行了两次复制。。如此捣腾是不是绕了弯路了?
为什么不直接由内核载入exec的目标程序,然后返回新进程id呢?

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
5 [报告]
发表于 2006-06-16 16:29 |只看该作者
原帖由 dulao5 于 2006-6-16 16:26 发表
to 2楼:
如果不执行,那么if如何得到exec的返回值??

to 3楼:
我是说实现起来CreateProcess更简单。而不是程序员调用简单。实现时, 比先fork复制一块内存,然后exec再载入覆盖这块内存,再加个写时复制技 ...



去看man手册.

If any of the exec functions returns, an error will have occurred.  The return value is -1, and the global  variable
       errno will be set to indicate the error.

论坛徽章:
0
6 [报告]
发表于 2006-06-16 16:33 |只看该作者
原帖由 dulao5 于 2006-6-16 16:26 发表
to 2楼:
如果不执行,那么if如何得到exec的返回值??

to 3楼:
我是说实现起来CreateProcess更简单。而不是程序员调用简单。实现时, 比先fork复制一块内存,然后exec再载入覆盖这块内存,再加个写时复制技 ...

在传统的 UNIX 程序中,fork 的目的在 99% 的情况下不是为了 exec。
因此,当然不能直接 load 新进程的可执行镜像。

论坛徽章:
0
7 [报告]
发表于 2006-06-16 16:41 |只看该作者
谢谢mq110 的提醒,看起来是返回值何时返回的问题我没搞清楚

to 莫愁 :
我依然感觉从init逐步fork调用其他程序的方式很别扭。
虽然你说99%不是为了exec,但是我还是觉得应该为创建新进程做个专门的系统调用

论坛徽章:
0
8 [报告]
发表于 2006-06-16 16:42 |只看该作者
原帖由 dulao5 于 2006-6-16 16:26 发表
to 2楼:
如果不执行,那么if如何得到exec的返回值??

to 3楼:
我是说实现起来CreateProcess更简单。而不是程序员调用简单。实现时, 比先fork复制一块内存,然后exec再载入覆盖这块内存,再加个写时复制技术进行优化。。进行了两次复制。。如此捣腾是不是绕了弯路了?
为什么不直接由内核载入exec的目标程序,然后返回新进程id呢?

exec 如果执行成功会返回值吗?看书没有?

fork 的作用只是“克隆”一个自身,有很多程序都只 fork 而不 exec 的,比如 apache。你可以把这看成 UNIX 的哲学:一个工具只做一件事,并且要把它做好。

PS:新建一个进程很容易嘛?你需要划一块内存、建立虚拟内存映像、读入程序文件、建立进程描述表、环境变量、标准输入输出、vnode table等等各种各样的初始配置。实际上先 fork 后 exec,正是 UNIX 创造者懒惰的表现...

[ 本帖最后由 isjfk 于 2006-6-16 16:43 编辑 ]

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
9 [报告]
发表于 2006-06-16 16:45 |只看该作者
原帖由 dulao5 于 2006-6-16 16:41 发表
谢谢mq110 的提醒,看起来是返回值何时返回的问题我没搞清楚

to 莫愁 :
我依然感觉从init逐步fork调用其他程序的方式很别扭。
虽然你说99%不是为了exec,但是我还是觉得应该为创建新进程做个专门的系统调用

要么接受它,
要么改变它!

论坛徽章:
0
10 [报告]
发表于 2006-06-16 16:48 |只看该作者
原帖由 dulao5 于 2006-6-16 16:41 发表
谢谢mq110 的提醒,看起来是返回值何时返回的问题我没搞清楚

to 莫愁 :
我依然感觉从init逐步fork调用其他程序的方式很别扭。
虽然你说99%不是为了exec,但是我还是觉得应该为创建新进程做个专门的系统调用

我记得好像是有,只不过把 fork 和 exec 包装了一下而已。很少用到。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP