PHP-控制进程数量和实际进程数不符

发布于 2017-01-19 12:47:20 字数 2095 浏览 1033 评论 2

最近学习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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夜无邪 2017-03-11 17:24:50

经过测试,确实如你说所,但不是可以稳定复现,对出现的这个情况大致做了下分析,

原因可能出现在 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;
}
}

偏爱自由 2017-01-26 14:04:45

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文