我正在尝试编写一个小脚本,该脚本将使用 symfony 组件 Process ( http://symfony.com/doc/current/components/process.html )管理一系列后台进程。
为了使其正常工作,我想处理发送到主进程的信号,主要是 SIGINT ( ctrl + c)。
当主进程收到此信号时,它应该停止启动新进程,等待所有当前进程退出,然后自行退出。
我成功地在主进程中捕获了信号,但问题是子进程也收到了信号并立即退出。
有没有办法改变这种行为或中断这个信号?
这是我演示该行为的示例脚本。
#!/usr/bin/env php
<?php
require_once __DIR__ . "/vendor/autoload.php";
use Symfony\Component\Process\Process;
$process = new Process("sleep 10");
$process->start();
$exitHandler = function ($signo) use ($process) {
print "Got signal {$signo}\n";
while ($process->isRunning()) {
usleep(10000);
}
exit;
};
pcntl_signal(SIGINT, $exitHandler);
while (true) {
pcntl_signal_dispatch();
sleep(1);
}
运行此脚本并发送信号(按 ctrl + c)将立即停止父进程和子进程)。
如果我用 isRunning 调用替换 while 循环,用进程上的等待方法调用替换睡眠,我得到一个 RuntimeException 说:进程已经用信号“2”发出信号。
如果我采取更手动的方法并使用 phps build in exec 执行子进程,我会得到我想要的行为。
#!/usr/bin/env php
<?php
require_once __DIR__ . "/vendor/autoload.php";
exec(sprintf("%s > %s 2>&1 & echo $! >> %s", "sleep 10", "/dev/null", "/tmp/testscript.pid"));
$exitHandler = function ($signo) {
print "Got signal {$signo}\n";
$pid = file_get_contents("/tmp/testscript.pid");
while (isRunning($pid)) {
usleep(10000);
}
exit;
};
pcntl_signal(SIGINT, $exitHandler);
while (true) {
pcntl_signal_dispatch();
sleep(1);
}
function isRunning($pid){
try{
$result = shell_exec(sprintf("ps %d", $pid));
if( count(preg_split("/\n/", $result)) > 2){
return true;
}
}catch(Exception $e){}
return false;
}
在这种情况下,当我发送信号时,主进程在退出之前等待它的子进程完成。
有什么方法可以获取 symfony 进程组件中的行为?