PHP-控制进程数量和实际进程数不符
最近学习php处理进程方面。
根据网上的资料,改写了一段代码。
代码功能:控制php最多产生的进程数目
但,实验的时候,随着运行时间的延长,发现了问题,自己没想清楚出问题的原因
下面是源代码。
这个实验,
需要在linux下,
并且php安装了pcntl模块,
可以通过 php -m|grep pcntl 查看是否安装
pcntl安装方法:http://cn2.php.net/manual/zh/pcntl.installation.php
declare(ticks = 1);
$max=5;
$child=0;
// function for signal handler
function sig_handler($signo) {
global $child;
switch ($signo) {
case SIGCHLD:#子进程中止信号
echo "SIGCHLD receivedn";
$child--;
break;
default:
echo "+++++++++++++++++++++++++n";
echo "other:{$signo}n";
echo "+++++++++++++++++++++++++n";
}
}
function bind_signal()
{
pcntl_signal(SIGCHLD, "sig_handler");
}
bind_signal();
// install signal handler for dead kids
#pcntl_signal(SIGCHLD, "sig_handler");#信息处理器,当发现子进程中止,执行sig_handler回调函数
while (1){
$pid=pcntl_fork();
if ($pid == -1) {
die("could not fork");
} else if ($pid) {// we are the parent
echo 'childNum:'.$child.', maxNum:'.$max."n";
$child++;
if ( $child >= $max ){
$dead_id = pcntl_wait($status);#阻塞,直到有子进程中止
echo 'child:'.$dead_id.' dead'.PHP_EOL;
# $child--;
}
echo 'after compare >>childNum:'.$child.', maxNum:'.$max."n";
} else {// we are the child
$cpid = posix_getpid();
$expire = rand(1, 5);#子进程生存时间
echo "t Starting new child | now we de have $child child processes | current pid:{$cpid} | expire {$expire}n";
sleep($expire);
exit;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
经过测试,确实如你说所,但不是可以稳定复现,对出现的这个情况大致做了下分析,
原因可能出现在 pcntl_signal(SIGCHLD, "sig_handler"); 也就是sig_handler这个信号处理函数上。因为处理sig_handler函数的执行并会阻塞其他语句执行,与其他语句是独立的,当sig_handler函数中出现比较耗时的计算,那么父进程控制语句中的
$dead_id = pcntl_wait($status);并不会等sig_handler函数处理完之后才去执行,所以导致
$child 值不正确,也就出现你像你所说的 6个子进程。
但是 sig_handler 函数中没有什么耗时的操作,只有简单的判断以及输出,其实这也是需要时间的,我这里的耗时指的的微秒级的。所以这个问题才不会稳定的复现。
可以尝试以下方法验证:
function sig_handler($signo) {
global $child;
switch ($signo) {
case SIGCHLD:#子进程中止信号
echo "SIGCHLD receivedn";
usleep(100000); //用延时来模拟,分别测试 usleep(10000);,usleep(1000000);
$child--;
break;
default:
echo "+++++++++++++++++++++++++n";
echo "other:{$signo}n";
echo "+++++++++++++++++++++++++n";
}
}
通过上边的测试,发现 完全不会阻塞其他程序的正常运行,也可以稳定的测试出子进程的控制不正确。
我觉得使用 pcntl_signal() 控制进程数是不正确的方法。应该在
$dead_id = pcntl_wait($status); 后 $child-- 操作才是正确的。完整代码:
$max=5;
$child=0;
while (1){
$pid=pcntl_fork();
if ($pid == -1) {
die("could not fork");
} else if ($pid) {// we are the parent
echo 'childNum:'.$child.', maxNum:'.$max."n";
$child++;
if ( $child >= $max ){
$dead_id = pcntl_wait($status);#阻塞,直到有子进程中止
echo 'child:'.$dead_id.' dead'.PHP_EOL;
$child--;
}
echo 'after compare >>childNum:'.$child.', maxNum:'.$max."n";
} else {// we are the child
$cpid = posix_getpid();
$expire = rand(1, 10);#子进程生存时间
echo "t Starting new child | now we de have $child child processes | current pid:{$cpid} | expire {$expire}n";
sleep($expire);
exit;
}
}
while循环的地方有问题,应该先$pid = pcntl_fork();之前对child加1
while (1){
$child++;
$pid=pcntl_fork();
if ($pid == -1) {
die("could not fork");
} else if ($pid) {// we are the parent
echo 'childNum:'.$child.', maxNum:'.$max."n";
if ( $child >= $max ){
$dead_id = pcntl_wait($status);#阻塞,直到有子进程中止
echo 'child:'.$dead_id.' dead'.PHP_EOL;
# $child--;
}
echo 'after compare >>childNum:'.$child.', maxNum:'.$max."n";
} else {// we are the child
$cpid = posix_getpid();
$expire = rand(1, 5);#子进程生存时间
echo "t Starting new child | now we de have $child child processes | current pid:{$cpid} | expire {$expire}n";
sleep($expire);
exit;
}
}
下面是我修改后的测试结果:
after compare >>childNum:5, maxNum:5
Starting new child | now we de have 6 child processes | current pid:10048 | expire 3
9425 8394 S root php wait.php
9444 9425 S root php wait.php
9445 9425 S root php wait.php
9446 9425 S root php wait.php
9447 9425 S root php wait.php