首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >关于vfork()系统调用?

关于vfork()系统调用?
EN

Stack Overflow用户
提问于 2017-07-25 09:51:47
回答 2查看 1.1K关注 0票数 3
代码语言:javascript
复制
#include <stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdio.h>
#include<stdlib.h>

int main()
{
   pid_t child_pid = vfork();

   if(child_pid < 0)
   {
       printf("vfork() error\n");
       exit(-1);
   }
   if(child_pid != 0)
   {
       printf("Hey I am parent %d\nMy child is %d\n",getpid(),child_pid);
       wait(NULL);
   }

   else
   {
       printf("Hey I am child %d\nMy parent is %d\n",getpid(),getppid());
       execl("/bin/echo","echo","hello",NULL);
       exit(0);
   }
   return 0;
}

产出:

代码语言:javascript
复制
 Hey I am child 4
 My parent is 3
 Hey I am parent 3
 My child is 4
 hello

我的问题是:为什么在执行父进程之后打印"hello“?我已经开始学习vfork()了。有人能帮我吗?

EN

回答 2

Stack Overflow用户

发布于 2017-07-25 10:10:36

执行父进程后,它将进入wait(NULL);,它将阻塞父进程,直到子进程调用execl()exit为止。

因此,当父进程被阻塞时,子进程正在调用execl(),因此在输出的末尾打印hello

代码语言:javascript
复制
#include <stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdio.h>
#include<stdlib.h>

int main()
{
pid_t child_pid = vfork();

if(child_pid < 0)
{
   printf("vfork() error\n");
   exit(-1);
}
if(child_pid != 0)
{
   printf("Hey I am parent %d\nMy child is %d\n",getpid(),child_pid);
   wait(NULL);
 }

 else
 {
   printf("Hey I am child %d\nMy parent is %d\n",getpid(),getppid());
   execl("/bin/echo","echo","hello",NULL);
   exit(0);
  }
 return 0;
  }

如果删除execl(),子进程将转到exit(0)hello将不会被打印。

而且,在执行execl()之后,它将创建一个新的进程,因此您在execl()之后编写的任何代码都不会被执行。根据手册页:-

exec()函数系列用新的进程映像替换当前进程映像。本手册中描述的函数是execve(2)的前端。(有关替换当前进程映像的详细信息,请参阅execve(2)手册页。)

票数 2
EN

Stack Overflow用户

发布于 2017-07-25 11:14:26

首先有一条建议:不要使用vfork()。在现代系统中,使用vfork()而不是fork()的优势很小。您显示的代码无法在vfork()中正常工作,因为它调用了未定义的行为。

POSIX.1:

vfork()函数具有与fork()相同的效果,但如果vfork()创建的进程修改用于存储来自vfork()的返回值的类型pid_t变量以外的任何数据,或者从调用vfork()的函数中返回,或者在成功调用_exit()exec()系列函数之前调用任何其他函数,则行为是未定义的。

因此,通过在子代码中调用printf(),您的代码已经没有定义。请注意,即使调用exit()也会导致未定义的行为,只允许使用_exit()

我假设您在Linux上尝试了这一点,它更多地定义了vfork()的行为,并解释了您所观察到的内容:

来自linux manual page

vfork()fork(2)的不同之处在于,调用线程被挂起,直到子线程终止为止(通常通过调用_exit(2),或者在传递致命信号之后调用_exit(2)),或者调用execve(2)。在此之前,子节点与其父节点共享所有内存,包括堆栈。

因此,在Linux上,您可以确保首先执行由vfork()创建的子进程,并且只通过调用execl() (在内部调用execve() )来执行,允许父进程继续运行。这就是为什么您在子输出之后看到父输出的原因。一旦父调用了wait(),它就一直等到子进程完成--此时,子节点被echo替换。

依赖这种行为使您的程序无法移植到不同的vfork()实现。对printf()的调用是可以的,因为Linux挂起了父进程,而对exit()的错误调用在这里并不重要:无论如何,在exec*()调用之后的任何事情都是不可访问的(这些函数永远不会返回,它们将替换为正在运行的程序)!

由于其怪异的语义和巨大的bug风险,vfork()在POSIX1.2008中被从POSIX中删除。一个安全和现代的POSIX替代vfork()的典型用法是exec*(),后面跟着的是posix_spawn()

总之,您真的不应该使用vfork()。使用fork()代替。删除对exit()的不可访问调用,您的程序看起来也很好。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45299735

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档