PHP:pcntl_fork 之后 proc_get_status 退出代码始终为 -1
我在父进程中的 pcntl_fork 之后使用 proc_get_status 时遇到问题。
这是一个使用 docker 和 PHP 7.4 的示例,但请注意 PHP 版本并不重要,至少从 PHP 7.2 到 PHP 8.1 结果是相同的。
设置
Dockerfile
FROM php:7.4
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
RUN chmod +x /usr/local/bin/install-php-extensions && \
install-php-extensions pcntl
运行:docker build -t php-pcntl-7.4 .
test.php
<?php
if ($argv[1] ?? false) {
pcntl_async_signals(true);
pcntl_signal(SIGCHLD, SIG_IGN);
$pid = pcntl_fork();
if ($pid === -1) {
throw new \RuntimeException('fork failed');
}
if ($pid === 0) {
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
throw new \Exception('child should be ignored');
}
pcntl_waitpid($pid, $childStatusCode);
}
function runCommand(string $command): void
{
$pipes = [];
$proc = proc_open($command, [['pipe', 'r'],['pipe', 'w'],['pipe', 'w']], $pipes);
do {
if (isset($status)) {
usleep(300000);
}
$status = proc_get_status($proc);
} while ($status['running']);
echo 'Command: ' . $command . PHP_EOL;
echo 'last proc_get_status exitcode: ' . $status['exitcode'] . PHP_EOL;
echo PHP_EOL;
}
echo 'PHP version: ' . PHP_VERSION . PHP_EOL;
runCommand('/bin/echo test');
runCommand('/bin/false');
测试之前不运行 fork
运行:docker run -it --rm -v $PWD:/workdir -w /workdir php-pcntl-7.4 php test.php
输出:
PHP version: 7.4.28
Command: /bin/echo test
last proc_get_status exitcode: 0
Command: /bin/false
last proc_get_status exitcode: 1
在之前运行 fork 进行测试
运行:docker 运行-it --rm -v $PWD:/workdir -w /workdir php-pcntl-7.4 php test.php 1
输出:
PHP version: 7.4.28
Command: /bin/echo test
last proc_get_status exitcode: -1
Command: /bin/false
last proc_get_status exitcode: -1
有谁知道为什么退出代码总是-1,以及是否有解决方法?
I'm having troubles with using proc_get_status after a pcntl_fork in the parent process.
Here's an example with docker and PHP 7.4, but note the PHP version does not matter, the result is the same from at least PHP 7.2 to PHP 8.1.
Setup
Dockerfile
FROM php:7.4
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
RUN chmod +x /usr/local/bin/install-php-extensions && \
install-php-extensions pcntl
Run: docker build -t php-pcntl-7.4 .
test.php
<?php
if ($argv[1] ?? false) {
pcntl_async_signals(true);
pcntl_signal(SIGCHLD, SIG_IGN);
$pid = pcntl_fork();
if ($pid === -1) {
throw new \RuntimeException('fork failed');
}
if ($pid === 0) {
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
throw new \Exception('child should be ignored');
}
pcntl_waitpid($pid, $childStatusCode);
}
function runCommand(string $command): void
{
$pipes = [];
$proc = proc_open($command, [['pipe', 'r'],['pipe', 'w'],['pipe', 'w']], $pipes);
do {
if (isset($status)) {
usleep(300000);
}
$status = proc_get_status($proc);
} while ($status['running']);
echo 'Command: ' . $command . PHP_EOL;
echo 'last proc_get_status exitcode: ' . $status['exitcode'] . PHP_EOL;
echo PHP_EOL;
}
echo 'PHP version: ' . PHP_VERSION . PHP_EOL;
runCommand('/bin/echo test');
runCommand('/bin/false');
Test without running a fork before
Run: docker run -it --rm -v $PWD:/workdir -w /workdir php-pcntl-7.4 php test.php
Output:
PHP version: 7.4.28
Command: /bin/echo test
last proc_get_status exitcode: 0
Command: /bin/false
last proc_get_status exitcode: 1
Test with running a fork before
Run: docker run -it --rm -v $PWD:/workdir -w /workdir php-pcntl-7.4 php test.php 1
Output:
PHP version: 7.4.28
Command: /bin/echo test
last proc_get_status exitcode: -1
Command: /bin/false
last proc_get_status exitcode: -1
Does anyone have an idea of why the exitcode is always -1, and if there is a workaround ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这似乎是 pcntl_signal(SIGCHLD, SIG_IGN) 调用中的错误。删除呼叫,问题就消失了。
由于 SIG_IGN 是 SIGCHLD 的默认值,因此很少需要它,这可能就是为什么以前没有注意到这一点。
This seems to be a bug in the pcntl_signal(SIGCHLD, SIG_IGN) call. Remove the call and the problem goes away.
As SIG_IGN is the default for SIGCHLD, it's rarely needed which is probably why this hasn't been noticed before.