等待所有的pids退出php

时间:2012-04-17 20:43:42

标签: php fork

我的问题是这个。我正在分配一个进程,以便加快磁盘上文件的访问速度。我将这些文件中的任何数据存储在本地桌面上的tmp文件中。理想情况下,在所有进程完成后,我需要访问该tmp文件并将该数据放入数组中。然后我取消链接tmp文件,因为它不再需要。我的问题是,在进入最后一组操作之前,似乎pcntl_wait()在执行完所有子进程之前都没有等待。所以我最终在一些随机过程完成之前取消链接该文件。

我似乎无法找到一种可靠的方法来等待所有进程干净地退出然后访问我的数据。

    $numChild       = 0;    
    $maxChild       = 20;   // max number of forked processes.

    // get a list of "availableCabs"

    foreach ($availableCabs as $cab) {

            // fork the process
            $pids[$numChild] = pcntl_fork();

            if (!$pids[$numChild]) {

                    // do some work     
                    exit(0);

            } else {

                    $numChild++;
                    if ($numChild == $maxChild) {

                            pcntl_wait($status);
                            $numChild--;

                    } 

            } // end fork   

    }

    // Below is where things fall apart. I need to be able to print the complete serialized data. but several child processes don't actually exit before i unlink the file.

    $dataFile = fopen($pid, 'r');

    while(($values = fgetcsv($dataFile,',')) !== FALSE) {
            $fvalues[] = $values;
    }

    print serialize($fvalues);

    fclose($dataFile);
    unlink($file);      

请注意,如果我们需要发布那些没有问题的内容,我会留下很多关于我实际在做什么的代码。

1 个答案:

答案 0 :(得分:9)

尝试重构代码,以便有两个循环 - 一个产生进程,一个等待它们完成。您还应该使用pcntl_waitpid()来检查特定的进程ID,而不是您当前使用的简单子计数方法。

这样的事情:

<?php

  $maxChildren = 20;   // Max number of forked processes
  $pids = array();     // Child process tracking array

  // Get a list of "availableCabs"

  foreach ($availableCabs as $cab) {

    // Limit the number of child processes
    // If $maxChildren or more processes exist, wait until one exits
    if (count($pids) >= $maxChildren) {
      $pid = pcntl_waitpid(-1, $status);
      unset($pids[$pid]); // Remove PID that exited from the list
    }

    // Fork the process
    $pid = pcntl_fork();

    if ($pid) { // Parent

      if ($pid < 0) {
        // Unable to fork process, handle error here
        continue;
      } else {
        // Add child PID to tracker array
        // Use PID as key for easy use of unset()
        $pids[$pid] = $pid;
      }

    } else { // Child

      // If you aren't doing this already, consider using include() here - it
      // will keep the code in the parent script more readable and separate
      // the logic for the parent and children

      exit(0);

    }

  }

  // Now wait for the child processes to exit. This approach may seem overly
  // simple, but because of the way it works it will have the effect of
  // waiting until the last process exits and pretty much no longer
  foreach ($pids as $pid) {
    pcntl_waitpid($pid, $status);
    unset($pids[$pid]);
  }

  // Now the parent process can do it's cleanup of the results