【问题标题】:Fork in perl but get exit status from a system call in the child process在 perl 中分叉,但从子进程中的系统调用中获取退出状态
【发布时间】:2011-04-28 03:35:20
【问题描述】:

我做什么:

  1. 对 cgi 脚本进行 ajax 调用。
  2. Cgi 脚本分叉,但父级立即返回响应消息。
  3. 孩子进行了系统调用,但需要退出代码和任何错误消息。

伪代码:

$SIG{CHLD} = ‘IGNORE’; # or waitpid($pid,0) in the parent process
$pid = fork();
if($pid == 0)
{
    close STDOUT; # So that the parent sends the response to the client right away.

    @errorMsgs = qx(tar up big directories over 50G…); # This can go on for a few minutes.

    if($? ==0) { Send a ‘success’ email } # Is always false ($? == -1)

    else { Send a ‘failure’ email }
}
elsif($pid){ sendResponse; waitpid($pid,0) if $SIG{CHLD} != 'IGNORE'; exit;}

我的问题:

由于 ($SIG{CHLD} = 'IGNORE') 将 qx() 设置为 -1,因此无法从 qx() 获取正确的返回码 ($?) 和任何错误消息。如果我删除 $SIG{CHLD} 语句,客户端网页不会收到来自父级的响应消息,直到子级被收割之后。

【问题讨论】:

  • 可能父输出被缓冲了。如果您忘记了 SIGCHLD 处理程序并确保设置了 $| = 1 会发生什么?
  • @mob:它在 Linux 上。我可以通过设置 $| 来发送响应但我读到不等孩子是一种不好的做法,它可能会导致僵尸。

标签: ajax perl fork exit qx


【解决方案1】:

您得到 -1 是因为您将 $SIG{CHLD} 设置为 IGNORE。通过这样做,你正在扼杀qx 捕获tar 的退出代码的能力......它会在不通知父进程(你的子进程)的情况下死亡。

测试很简单:

perl -e '$SIG{CHLD} = "IGNORE"; system("ps"); print "Finished with $?\n";

这给出-1。

perl -e 'system("ps"); print "Finished with $?\n";

这给出 0。

如果您真的需要$SIG{CHLD} = 'IGNORE',那么只需在您拨打qx 之前使用$SIG{CHLD} = 'DEFAULT'

另外,请确保您使用的是 tar 的完整路径(例如 /bin/tar),以防万一您的路径中没有 /bin 并且它无法执行。但是,我假设这没关系,因为您没有说明您的 tar 文件没有被创建。

【讨论】:

  • 是的,tar 的完整路径可以正常工作。将 $SIG{CHLD} 设置为 undef 解决了它。我将 $SIG{CHLD} 设置为 IGNORE 的原因是为了避免创建僵尸。但这解决了它。非常感谢!
【解决方案2】:

好吧,如果您在子部分(即在$pid == 0 之后)将$SIG{CHLD} 重置为undef,它不会影响父进程,对吧?

【讨论】:

  • 那行得通。非常感谢 !上面马克的声明 - “这样做,你正在扼杀 qx 捕获 tar 退出代码的能力......它会在不通知父进程(你的子进程)的情况下死亡。” - 几乎解释了发生了什么。孩子失去了将任何状态返回给其父母的能力。
猜你喜欢
  • 1970-01-01
  • 2011-10-24
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-29
相关资源
最近更新 更多