PHP (pseudo)Threads

Brakuje mi w PHP wielowątkowości. Jakoś autorom nie jest pilno do tego a czasem by się przydało.

Z potrzeby chwili powstało coś takiego:


class Thread
{
private $token = false;
private $semaphore = false;
private $data = array();

function __construct()
{
$data = array();
$SHM_KEY = ftok(__FILE__,chr(4));

$this->semaphore = sem_get($SHM_KEY,1);
$this->token = shm_attach($SHM_KEY,1024,0666);

@shm_remove($this->token);
shm_attach($this->token);
@shm_put_var($this->token,1,$data);
}
function __call($method,$params)
{
if(substr($method,0,3) === '___')
{
$pid = pcntl_fork();

if($pid)
{
$method = substr($method,3);
@call_user_func_array(array(&$this,$method),$params);
}
}
}
function __set($key,$value)
{
if(substr($key,0,3) === '___')
{
$key = substr($key,3);
sem_acquire($this->semaphore);

$data = @shm_get_var($this->token,1);
$data[$key] = $value;

@shm_put_var($this->token,1,$data);

sem_release($this->semaphore);
}
$this->data[$key] = $value;

return $value;
}
function __get($key)
{
if(substr($key,0,3) === '___')
{
$key = substr($key,3);
$data = @shm_get_var($this->token,1);

if(isset($data[$key]))
{
$ret = $data[$key];
$this->data[$key] = $ret;
}
else
{
$ret = $this->data[$key];
}
}
else
{
$ret = $this->data[$key];
}

return $ret;
}
}

Korzysta się z tego dość prosto.
Przykład klasy wykorzystującej wątkowanie:

class Thread_Test extends Thread
{
function loop1()
{
for($this->___i1=0;true;$this->___i1++)
{
sleep(3);
}
}
function loop2()
{
for($this->i2=0;true;$this->i2++)
{
sleep(2);
}
}
function loop3()
{
for($this->i3=0;true;$this->i3++)
{
echo "loop1: {$this->___i1} loop2: {$this->___i2} loop3: {$this->___i3} loop4: {$this->___i4}\n";
sleep(1);
}
}
function loop4()
{
for($this->___i4=0;true;$this->___i4++)
{
}
}
}

i właściwe wywołanie:


$t = new Thread_Test();

$t->___loop1();
$t->___loop2();
$t->___loop4();
$t->loop3();

while(1)
{
sleep(1);
echo "MAIN {$t->___i1} \n";
}

Jak widać ;P aby wywołać metodę jako osobny wątek dodajemy przed jej nazwą trzy znaki podkreślenia, np $t->___waitLongTime(); To samo tyczy się zmiennych. Zmienne zapisane tradycyjnie ($t->zmienna) są zmiennymi lokalnymi wątku, zmienne z trzema znakami podkreślenia ($t->___zmienna) są zmiennymi współdzielonymi w klasie, dostępnymi dla wszystkich wątków.

Dostęp do zmiennych współdzielonych jest bardzo wolny. Spowodowane jest to koniecznością synchronizowania zapisów do zmiennych.