public function run() { echo 'Hello, I am a thread with id ' . $this->getPid() . "!\nTrying to lock the critical section\n"; $lock = new GPhpThreadLockGuard($this->criticalSection); echo "=--- locked " . $this->getPid() . "\n"; $this->criticalSection->addOrUpdateResource('IAM', $this->getPid()); $criticalSection2 = new GPhpThreadCriticalSection(); $a = new MyThreadThread($criticalSection2, true); $b = new MyThreadThread($criticalSection2, true); $a->start(); $b->start(); $a->join(); $b->join(); $criticalSection2->lock(); echo "=###= Last internal cs value: " . $criticalSection2->getResourceValue('IAM') . "\n"; $criticalSection2->unlock(); $this->criticalSection->addOrUpdateResource('IAMNOT', '0xdead1'); $this->criticalSection->removeResource('IAMNOT'); echo "=--- unlocked " . $this->getPid() . "\n"; GPhpThread::resetThreadIdGenerator(); $ms2 = new MyStuff('heavy thread 1'); }
} } echo "Master main EP " . getmypid() . "\n"; $criticalSection = new GPhpThreadCriticalSection(); $criticalSection->cleanPipeGarbage(); // remove any garbage left from any ungracefully terminated previous executions $threadPool = array(); $tpSize = 20; for ($i = 1; $i <= $tpSize; ++$i) { $threadPool[$i] = new MyThread($criticalSection, true); } // xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_NO_BUILTINS); GPhpThread::BGN_HIGH_PRIOR_EXEC_BLOCK(); // this will result fast thread creation but, because of that all threads will try // to reach the critical section at once in some cases may take twice the time for each one in order to lock the critical section for ($i = 1; $i <= $tpSize; ++$i) { $threadPool[$i]->start(); echo "{$i} of {$tpSize} started\n"; } GPhpThread::END_HIGH_PRIOR_EXEC_BLOCK(); for ($i = 1; $i <= $tpSize; ++$i) { $threadPool[$i]->join(); } // $xhprof_data = xhprof_disable(); echo "\n\n---The last writing in the critical section was done by thread---\n"; echo "---" . $criticalSection->getResourceValueFast('IAM') . "\n\n"; //uasort($xhprof_data, function ($a, $b) { // if ($a['wt'] > $b['wt']) return -1; // else return 1; //}); // print_r($xhprof_data);
/** * Waits for executing thread to return. * @param bool $useBlocking If is set to true will block the until the thread returns. * @return bool True if the thread has joined otherwise false. */ public final function join($useBlocking = true) { // {{{ if (!$this->amIStarted) { return false; } if ($this->amIParent()) { $status = null; $res = 0; if ($useBlocking) { GPhpThread::BGN_HIGH_PRIOR_EXEC_BLOCK(); while (($res = pcntl_waitpid($this->childPid, $status, WNOHANG)) == 0) { GPhpThreadCriticalSection::dispatch(); usleep(mt_rand(10000, 40000)); } if ($res > 0 && pcntl_wifexited($status)) { $this->exitCode = pcntl_wexitstatus($status); } else { $this->exitCode = false; } if ($this->criticalSection !== null) { $this->criticalSection->finalize($this->uniqueId); } $this->childPid = null; $this->_childPid = null; $this->amIStarted = false; GPhpThread::END_HIGH_PRIOR_EXEC_BLOCK(); } else { $res = pcntl_waitpid($this->childPid, $status, WNOHANG); if ($res > 0 && $this->criticalSection !== null) { $this->criticalSection->finalize($this->uniqueId); } if ($res > 0 && pcntl_wifexited($status)) { $this->exitCode = pcntl_wexitstatus($status); if ($this->criticalSection !== null) { $this->criticalSection->finalize($this->uniqueId); } $this->amIStarted = false; } else { if ($res == -1) { $this->exitCode = false; } } if ($res != 0) { if ($this->criticalSection !== null) { $this->criticalSection->finalize($this->uniqueId); } $this->childPid = null; $this->_childPid = null; } } return $res; } if ($this->childPid == -1) { return false; } exit(255); }