- 论坛徽章:
- 0
|
小弟最近刚开始研究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太伟大了后人一直没有超越当年的前辈,从而不敢逾越?
- 。。。。。
- int main(int argc, char * argv[], char * envp[])
- {
- pid_t cpid;
- char sub_arg[256] = "-l";
- if(cpid = fork() == 0)
- {
- ////注意这里,if是需要execlp函数返回的,if编译后的比较语句应该在execlp返回后执行
- if(execlp("./sub", sub_arg, NULL) < 0)
- perror("execlp error");
- //经过我测试,这段代码没有执行,没有输出,也没有写文件
- if(-1 == printf("\n exec end \n"))
- {//记录日志,防止printf由于标准输出可能已经被关闭导致的失败
- FILE *fp = fopen("log", "w+");
- if(fp==NULL){
- perror("log error");
- exit(0);
- }
- fputs("run log", fp);
- fclose(fp);
- }
- }
- else
- {
- int i=0;
- wait(&i);
- printf("main end\n");
- }
- }
复制代码
下面是另一段测试代码,说明exec系列函数语义如此特别,导致这样的代码不能执行:
- int main(int argc, char * argv[], char * envp[])
- {
- char sub_arg[256] = "-l";
- if(execlp("ls", sub_arg, NULL) < 0)
- perror("execlp error");
- //下面的代码不会执行了, 我们会看到程序仅仅输出了一次 ls -l 的结果
- if(execlp("ls", sub_arg, NULL) < 0)
- perror("execlp error");
- if(execlp("ls", sub_arg, NULL) < 0)
- perror("execlp error");
- }
复制代码 |
|