【问题标题】:How atomic the fork() syscall actually is?fork() 系统调用实际上有多原子?
【发布时间】:2019-04-26 08:20:23
【问题描述】:

假设check_if_pid_exists(pid) 在存在具有这种 pid 的进程时返回 true(但可能尚未运行),或者在没有具有这种 pid 的进程时返回 false >,当fork() 返回子pid 时,父代码中是否有机会出现竞争条件,但是内核没有机会初始化数据结构以便check_if_pid_exists(child) 返回错误的?或者也许在从fork() 返回之后,我们可以保证check_if_pid_exists(pid) 返回 true?

pid_t child = fork();

if (child == 0) {
  /* here the child just busy waits */
  for (;;)
    ;
}

if (child > 0) {
  /* here the parent checks whether child PID already exists */
  check_if_pid_exists(child);
}

【问题讨论】:

  • 如果外部事件真的很快杀死了孩子(例如 systemtap 脚本监控分叉),check_if_pid_exists(child) 可能会返回 false。
  • 正确,谢谢。但是假设没有“第三方”代理杀死我们的进程?
  • 它可能被第一方杀死,比如资源限制
  • 我认为,由于内核旨在适应父级在 fork 调用 wait 系统调用后发出的前两条指令的情况,因此内核几乎可以肯定到那时已经完全设置了子级分叉返回。

标签: c linux linux-kernel operating-system


【解决方案1】:

没有。

fork() 在新任务创建完成后返回,并且如父级所期望的那样可见。否则大多数事情都行不通。

该进程是否有机会运行或已经启动了一段时间,目前尚不清楚。一旦发生这种情况,您就会收到SIGCHLD 信号,从而知道孩子是否已经完成。

如果处理不当,您可以与SIGCHLD 进行比赛。也就是说,您应该忽略SIGCHLD 信号,调用fork(),适当地保存结果,以便您拥有孩子的PID(即分配一个结构来保存孩子pid_t 值),然后使用其中之一wait() 函数可以知道孩子是否死亡。

假设您的fork()ed 进程预计会运行一段时间,那么

check_if_pid_exists(child) == true

在 99.9999% 的情况下可能是正确的(实际上,假设父母可以控制孩子预计何时退出,则应在 100% 的情况下做到这一点)。

正如其他人所说,很多事情都会阻止新进程运行:

  • 内存不足
  • 你已经开始了太多的孩子
  • 孩子尝试做某事,遇到致命错误并退出
  • 某些第三方事物阻止了fork()
  • ...

另外,fork() 可能会返回 -1,以防它无法创建孩子。

但是,如果问题是关于:我如何跟踪孩子的一生?那么正确的答案是让父母检查它是否死亡。您不应该依赖诸如check_if_pid_exists() 之类的函数来搜索/proc/... 下的进程或类似的实现(请参阅waitid),因为这样的函数可能会确定进程仍在运行,然后进程死了,然而该函数仍然返回 true...

// ignore SIGCHLD
struct sigaction sa, chld;
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
__sigemptyset (&sa.sa_mask);
sigaction(SIGCHLD, &sa, NULL);

[...]

int child_is_running = 0;

[...]

pid_t child = fork();
if(child == 0) ...do stuff in the child...

if(child < 0) ...handle error...

int child_is_running = 1;

[...]

wait(...);

if(...child exited...) child_is_running = 0;

现在你可以写一个保险箱check_if_pid_exists()

int check_if_pid_exists()
{
    return child_is_running;
}

在我的示例中,我只允许一个孩子。如果您需要多个,那就需要一个更好的方案(可能是一个结构来保存孩子信息和某种表格或所有孩子的链接列表)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-21
    • 1970-01-01
    • 1970-01-01
    • 2011-06-10
    • 1970-01-01
    相关资源
    最近更新 更多