【问题标题】:return value in vfork() system callvfork() 系统调用中的返回值
【发布时间】:2012-03-10 00:20:41
【问题描述】:

考虑以下代码:

int main()
{
  int pid;
  pid=vfork();
  if(pid==0)
     printf("child\n");
  else
     printf("parent\n");
  return 0;
  }

在vfork()的情况下,父进程和子进程使用的地址空间相同,所以变量pid的单个副本应该在那里。现在我无法理解这个 pid 变量如何具有 vfork() 返回的两个值,即子级为零,父级非零?

在 fork() 的情况下,地址空间也会被复制,并且每个孩子和父母都有两个 pid 变量的副本,所以我可以理解在这种情况下,两个不同的副本可以有不同的值fork() 返回,但在 vfork() 的情况下无法理解 pid 如何具有 vfork() 返回的两个值? p>

【问题讨论】:

  • 那是致命的——你可以在vfork()'d 孩子中使用exec() 或_exit(),但仅此而已。几乎所有其他事情都会导致未定义的行为。建议:不要使用vfork();事实上,我什至不会费心去学习如何安全地使用它。就像gets(),一个最好假装不存在的功能。
  • @JonathanLeffler: vfork() 对于无 MMU 系统非常有用。
  • 是的,先生,我同意你的观点,我们不应该使用它,但我使用 vfork 来解决创建进程树和不同级别树的进程之间通信的一个问题,在这种情况下 vfork 很有用取一些全局变量。我会保留你的建议。
  • @L.ppt:嗯。不,这是对 vfork() 的不好使用。最好使用一些真正的 IPC(共享内存、套接字、管道……),或者,如果您真的知道自己在做什么,可以使用线程。
  • 我会翻译 R.. 的评论:vfork() 对于从 Java 生成进程很有用(你还能在哪里找到如此大的地址空间浪费?),而且确实 Java 1.7 似乎有添加了对vfork() 和posix_spawn() 的支持。

标签: c operating-system system-calls systems-programming


【解决方案1】:

没有 2 个副本。当你调用vfork 时,父进程冻结,而子进程执行它的操作(直到它调用_exit(2) 或execve(2))。所以在任何时候,只有一个 pid 变量。

附带说明,您所做的事情是不安全的。 The standard 拼写清楚:

vfork() 函数应该等同于 fork(),除了 如果由 vfork() 创建的进程,则行为未定义 修改除用于存储的 pid_t 类型变量以外的任何数据 vfork() 的返回值,或从其中的函数返回 vfork() 被调用,或在成功之前调用任何其他函数 调用 _exit() 或 exec 系列函数之一。

作为补充说明,vfork 已从 SUSv4 中删除 - 使用它真的没有意义。

【讨论】:

  • 这意味着在使用 vfork 时,创建的进程可以修改 pid_t 变量类型的值,因此当子退出并且父进程如何或由谁恢复之前的 pid_t 变量已恢复?? ?
  • @L.ppt 当父级继续使用pid_t时会存储子级的PID。
  • @L.ppt:编译器特别对待从vfork() 返回的pid_t 变量。它总是在一个寄存器上,不会溢出到内存中。
  • 我看不出有多么需要特殊处理。父级的返回发生在子级完成使用父级的内存之后,因此将看到新的返回值。唯一必须保存在vfork 的寄存器中的是返回地址,因为如果返回地址只是保存在堆栈中,孩子可能会破坏它。
  • @R..:这是有道理的。似乎我对 "modifies any data than a variable of type pid_t" 的阅读过多。所以vfork()需要你提到的libc级支持(保存/恢复寄存器中的返回地址),并且可能不允许对调用vfork()的函数进行一些编译器优化(GCC似乎不允许尾调用优化,全局公共子表达式消除并跳过调用vfork()或setjmp()的函数。
猜你喜欢
  • 1970-01-01
  • 2012-02-11
  • 1970-01-01
  • 2012-10-07
  • 2014-12-10
  • 2012-05-07
  • 2021-05-01
  • 2012-08-20
相关资源
最近更新 更多