Code Coverage  | 
      ||||||||||
Classes and Traits  | 
       Functions and Methods  | 
       Lines  | 
      ||||||||
| Total |         | 
       0.00%  | 
       0 / 1  | 
               | 
       0.00%  | 
       0 / 5  | 
       CRAP |         | 
       0.00%  | 
       0 / 41  | 
      
| MultiProcessor |         | 
       0.00%  | 
       0 / 1  | 
               | 
       0.00%  | 
       0 / 5  | 
       182.00 |         | 
       0.00%  | 
       0 / 41  | 
      
| __construct |         | 
       0.00%  | 
       0 / 1  | 
       2.00 |         | 
       0.00%  | 
       0 / 1  | 
      |||
| run |         | 
       0.00%  | 
       0 / 1  | 
       42.00 |         | 
       0.00%  | 
       0 / 21  | 
      |||
| addChild |         | 
       0.00%  | 
       0 / 1  | 
       2.00 |         | 
       0.00%  | 
       0 / 2  | 
      |||
| startChildren |         | 
       0.00%  | 
       0 / 1  | 
       6.00 |         | 
       0.00%  | 
       0 / 7  | 
      |||
| forkChild |         | 
       0.00%  | 
       0 / 1  | 
       12.00 |         | 
       0.00%  | 
       0 / 10  | 
      |||
| <?php | |
| /** | |
| * 並列実行ドライバ | |
| * | |
| * Linuxの fork&exec を利用したものなのでWindowsでは動作しない。 | |
| * pcntl拡張が必要。 | |
| * | |
| * @uses pcntl | |
| */ | |
| class MultiProcessor | |
| { | |
| /** | |
| * 登録された子プロセスのリスト | |
| * | |
| * <pre> | |
| * executable => PATH/TO/EXECUTABLE | |
| * args => array(arg1, arg2...) | |
| * </pre> | |
| * @var array | |
| */ | |
| private $childProcesses = array(); | |
| /** | |
| * 実行中の子プロセスのリスト | |
| * <pre> | |
| * pid => forked => true/false | |
| * args => array(arg1, arg2...) | |
| * </pre> | |
| * @var array | |
| */ | |
| private $pids = array(); | |
| /** | |
| * | |
| */ | |
| public function __construct() { | |
| } | |
| /** | |
| * 登録された子プロセスを fork&exec する | |
| * | |
| * @return bool 子プロセス全てが正常終了(0)したか否か | |
| * @throws Exception pcntl拡張がインストールされていない | |
| * @throws Exception fork失敗 | |
| */ | |
| public function run() { | |
| if(!function_exists('pcntl_fork')) { | |
| throw new Exception('pcntl extension not installed.'); | |
| } | |
| // --enable-sigchild のハンドラに食われないよう自前でブロック | |
| pcntl_sigprocmask(SIG_BLOCK, array(SIGCHLD)); | |
| if(count($this->childProcesses) === 0) { | |
| return false; | |
| } | |
| // fork & exec | |
| $this->startChildren(); | |
| // wait | |
| $arrExited = array(); | |
| foreach($this->pids as $pid=>$dummy) { | |
| pcntl_waitpid($pid, $status, WUNTRACED); | |
| //echo $pid, ":", pcntl_wexitstatus($status), "\n"; | |
| $arrExited[$pid] = pcntl_wexitstatus($status); | |
| } | |
| foreach($arrExited as $pid=>$status) { | |
| if($status !== 0) { | |
| return false; | |
| break; | |
| } | |
| } | |
| return true; | |
| } | |
| /** | |
| * 子プロセスを登録する | |
| * | |
| * $executableFullpath は実行可能でなければならない。 | |
| * interpreter, permissionをよく確認すること。 | |
| * | |
| * @param string $executableFullpath 実行可能ファイルのfullpath | |
| * @param string[] $args (optional) 引数 | |
| */ | |
| public function addChild($executableFullpath, array $args=array()) { | |
| $this->childProcesses[] = array('executable'=>$executableFullpath, 'args'=>$args); | |
| } | |
| protected function startChildren() { | |
| $numOfChildren = count($this->childProcesses); | |
| foreach($this->childProcesses as $child) { | |
| $childPid = $this->forkChild($child['executable'], $child['args']); | |
| $this->pids[$childPid]['forked'] = true; | |
| $this->pids[$childPid]['args'] = $child['args']; | |
| } | |
| } | |
| /** | |
| * fork & exec | |
| * | |
| * オーバレイをここでカプセル | |
| * @param string $executable | |
| * @param string[] $args | |
| * @return int process id | |
| * @throws \Exception fork failed | |
| */ | |
| protected function forkChild($executable, $args) { | |
| $pid = pcntl_fork(); | |
| if ($pid === -1) { | |
| throw new \Exception('Fork failed.'); | |
| } elseif ($pid > 0) { | |
| // Parent | |
| //echo "Forking child...\n"; | |
| } else { | |
| // Child | |
| pcntl_exec($executable, $args); | |
| // ここに来たということは pcntl_exec 失敗 | |
| exit(255); | |
| } | |
| return $pid; | |
| } | |
| } |