7

*下面答案中的解决方案*

我在 multifork php 脚本中限制子级时遇到了问题……似乎最后一个子级永无止境……我真的很累,找不到错误,你能帮忙吗?很多时候都没有结束...

<?php
declare(ticks = 1);

$max=5;
$child=0;

function sig_handler($signo) {
    global $child;
    switch ($signo) {
        case SIGCHLD:
        $child -= 1;
        echo "[-]";
    }
}

pcntl_signal(SIGCHLD, "sig_handler");

$found = array(1,2,3,4,5,6,7,8,9,10,11,12);

echo "LETS GO!\n";

foreach($found as $item){

            while ($child >= $max) {
            sleep(1);
        }

        $child++;
        echo "[+]";
        $pid=pcntl_fork();

        if($pid){
        }else{ // CHILD
            sleep(rand(1,5));
            echo "[~]";
            exit(0);
        }

}

while($child != 0){
    echo "($child)";
    sleep(1);
}

echo "THE END.\n"

?>

大多数时候的结果是:

[+][+][+][+][+][~][-][+][~][-][+][~][-][+][~][-][+][~][-][+][~][-][+][~][~][~][-][+]    (5)[-](4)(4)[~][-](3)[~][-](2)(2)[~](2)[-](1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)... etc etc ...

似乎最后一个孩子根本没有结束,或者至少它没有触发 sig 处理程序......

  • [+] <- 就在分叉之前 - 计数:12
  • [~] <- 就在孩子退出之前 - 计数:12
  • [-] <- 子退出后的 sig 处理程序 - 计数:11

帮助?

PS。奇怪的是,它有时确实会结束。

4

1 回答 1

7

好的找到了解决方案:

function sig_handler($signo){
  global $child;
  switch ($signo) {
    case SIGCLD:
      while( ( $pid = pcntl_wait ( $signo, WNOHANG ) ) > 0 ){
        $signal = pcntl_wexitstatus ($signo);
        $child -= 1;
        echo "[-]";       
      }
    break;
  }
}

问题在于在 UNIX 系统上处理信号的方式。在相似时间发送的所有信号都被分组为一个。上面的函数解决了这个问题。不仅如此……当孩子立即退出时,它不再出现段错误(某些 PHP 配置/版本中的“zend_mm_heap 已损坏”错误)。在以前的情况下也是如此。

PS。我应该删除这个问题,但我会将解决方案留给遇到类似问题的每个人,因为 PHP 脚本中的多线程对于某些任务非常有用。

于 2013-07-08T13:00:25.540 回答