I have been at this for over an hour, I have read everything under the sun about multi-threading in PHP, and I am lost when it comes to returning values to the parent thread. I have been practically brute forcing different combinations of ways I can come up with to pass variables back to the parent thread with zero success. I am not even sure if it is possible at this point.
I have tried static classes/methods/vars with a return, callbacks, anonymous methods, invokes, and nothing is working, I continue to get an empty array when the code finishes executing.
Attempt 1) I created a class called Results, with a static method that assigned a value to a static var array, with another static method to return all of the data when the code was finished executing, a print_r showed the data being added to the static var array, however, when the script was finished executing the static processData method returned an empty array.
Attempt 2) I removed the static elements from the Results class, and placed it in the TaskManager, using an anonymous method as a callback, I was able to return values to the TaskManager, but again, when the code was finished executing, an empty array.
Attempt 3) I created a global anonymous method to use as a callback, again, values are passed to the callback method, but you guessed it, empty array when the code was finished executing.
I am listing three attempts, but really, its been more like 20 attempts at this; I am at my wits end, any help at all is greatly appreciated.
Here is the code I have been working with.
<?php
/**
* author : Marc Quinton / April 2008.
*
* a simple task management framework using pcntl_fork, pcntl_wait.
*
* - see at bottom for a sample usage.
* - you shoud overring Task class (SleepingClass is an example), and manage them in a pool, using taskManager
*/
error_reporting(E_ALL);
class Results {
var $datas = array();
public function data($data)
{
$this->datas[] = $data;
}
public function processResults()
{
foreach($this->datas as $data)
{
print_r($data);
}
}
}
class Task {
protected $data;
protected $pid;
protected $ppid;
function __construct(){
}
function fork(){
$pid = pcntl_fork();
if ($pid == -1)
throw new Exception ('fork error on Task object');
elseif ($pid) {
# we are in parent class
$this->pid = $pid;
# echo "< in parent with pid {$his->pid}
";
} else{
# we are is child
$this->run();
}
}
function run(){
# echo "> in child {$this->pid}
";
# sleep(rand(1,3));
$this->ppid = posix_getppid();
$this->pid = posix_getpid();
}
# call when a task in finished (in parent)
function finish(){
echo "task finished {$this->pid}
";
}
function pid(){
return $this->pid;
}
}
class SleepingTask extends Task{
public $mybl;
public $data;
public $cback;
function __construct($bl, $cb){
$this->cback = $cb;
$this->mybl = $bl;
}
function run(){
global $callback;
parent::run();
echo "My BL ID: " . $this->mybl . " /END BL ID
";
$callback(array('whoa' => $this->mybl));
sleep(rand(1,2));
exit(0);
}
}
class TaskManager{
protected $pool;
protected $datas = array();
function __construct(){
$this->pool = array();
}
function add_task($task){
$this->pool[] = $task;
}
function run(){
foreach($this->pool as $task){
$task->fork();
}
# print_r($this);
# sleep(60);
while(1){
echo "waiting
";
$pid = pcntl_wait($extra);
if($pid == -1)
break;
echo ": task done : $pid
";
$this->finish_task($pid);
}
echo "processes done ; exiting
";
}
function finish_task($pid){
if($task = $this->pid_to_task($pid)) {
$task->finish();
}
}
function pid_to_task($pid){
foreach($this->pool as $task){
if($task->pid() == $pid)
return $task;
}
return false;
}
}
$datas = array();
$callback = function ($data) {
print_r($data);
global $datas;
$datas[] = $data;
};
$manager = new TaskManager();
for($i=0 ; $i<10 ; $i++)
$manager->add_task(new SleepingTask($i, $callback));
$manager->run();
print_r($datas);
exit(0);
?>