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; | |
} | |
} |