I have run into a situation with pthreads.Consider the following script:
<?php
class W extends \Worker {
public function run()
{
echo "worker started\n";
}
}
clasds S extends \Stackable {
public function run()
{
echo "stackable executed\n";
}
}
class x{
protected $workers;
protected $i;
public function __construct()
{
$this->workers = array();
$this->i = 0;
}
public function go()
{
$thread = $this->spawn();
$j = new S;
$thread->stack($j);
//$thread->shutdown();
}
public function spawn()
{
$this->i !== 0 ? $n=$this->i++ : $n=$this->i;
$thread = new W;
$this->workers[$n] = $thread;
$thread->start();
return $thread;
}
}
$exe = new x;
$exe->go();
php crashes.2 ways to solve the issue, either:
uncommenting
$w->shutdown();
which means the workers one creates are not reusable, or commenting out
$this->c[$n] = $w;
which means not saving workers in an array.
I do not understand what is going on here.must one call shutdown on a worker?why does attempting to store
the worker in an array lead to a crash?
Related
I am working on improving a process in php so I resorted into using multithreading using Worker to manage my threads. But the threads in the worker executes one after the other not concurrently.
This is my sample code
namespace App\Engine\Threads\ThreadClass;
class StatePaperAttendancePDFThread extends \Threaded
{
private $write_folder_name;
private $center_code;
private $paper_id;
private $title;
public function __construct($write_folder_name, $center_code, $paper_id, $title)
{
$this->write_folder_name = $write_folder_name;
$this->center_code = $center_code;
$this->paper_id = $paper_id;
$this->title = $title;
}
public function run(){
echo " Retrieving paper attendance ".$this->center_code." ".$this->paper_id." ".\Thread::getCurrentThreadId()." ".date("H:i:s:u").PHP_EOL;
$artisan = 'C:/xampp/htdocs/attendance/artisan';
$cmd = "php $artisan attendancereport:center $this->write_folder_name $this->center_code $this->paper_id $this->title";
$return = exec($cmd, $output, $return_var);
echo $return;
}
}
foreach ($centers as $i=>$center){
$center_code = $center->getCenterCode();
$thread = new StatePaperAttendancePDFThread($folder_name, $center_code, $paper_id, $title);
$worker->stack($thread);
}
$worker->start(PTHREADS_INHERIT_ALL ^ PTHREADS_INHERIT_CLASSES);
$worker->shutdown();
but when I monitor it from the CLI using the time been printed I can see that none of the threads starts together. They all starts with some seconds interval
Please what am I missing
I was able to solve my problem by creating a customized Thread Pool Executor as below. Please I am open to suggestions and Improvement
class ThreadPoolExecutor{
private $poolSize;
private $threadPool;
private $done = false;
private $workingThreads;
public function __construct($poolSize, array $threadPool)
{
$this->poolSize = $poolSize;
$this->threadPool = $threadPool;
}
public function execute()
{
$this->parametersOk();
try {
while (!empty($this->threadPool)) {
$this->extractThreads();
foreach ($this->workingThreads as $thread) {
$thread->start(PTHREADS_INHERIT_ALL ^ PTHREADS_INHERIT_CLASSES);
}
foreach ($this->workingThreads as $thread) {
$thread->join();
}
}
$this->done = true;
} catch (\Exception $ex) {
var_dump($ex->getMessage());
}
}
private function parametersOk()
{
if (!is_array($this->threadPool))
throw new \RuntimeException("threadPool expected to be an array of threads");
if (count($this->threadPool) <= 0)
throw new \RuntimeException("expected at least an element in threadPool");
foreach ($this->threadPool as $thread) {
if (!is_subclass_of($thread, \Thread::class, false)) {
throw new \RuntimeException(" an element of threadPool does not extend class \\Thread");
}
}
if ($this->poolSize > count($this->threadPool)) {
throw new \RuntimeException("The number of threads set to execute can not be greater than the threadPool");
}
return true;
}
private function extractThreads()
{
$this->workingThreads = [];
$this->workingThreads = array_slice($this->threadPool, 0, $this->poolSize);
for ($i = 0; $i < count($this->workingThreads); $i++) {
array_shift($this->threadPool);
}
}
public function isDone()
{
return $this->done;
}
}
I will appreciate any addition or correction to this.
I want to create a class that can remove duplicate items but uses pthreads I have an array with some duplicated lines and put them into a thread each line and here is my code.
header("Content-type: text/plain");
class Arr {
public $my_variable = array();
public function add($value) {
$this->my_variable[$value] = 1;
return $this->my_variable;
}
public function check($value)
{
if(isset($this->my_variable[$value])){
return true;
} else {
return false;
}
}
}
class workerThread extends Thread
{
public $arr;
public function __construct($i){
$this->i = str_replace("\r","",$i);
$this->i = str_replace("\n","",$this->i);
$this->arr = new Arr();
}
public function run()
{
if($this->arr->check($this->i)!==true)
{
$add = $this->arr->add($this->i);
echo date('H:i:s') . ' - '. $this->i . " - (".count($add).")\r\n";
}
}
}
$mailExp = array(
'talunays#gmail.com',
'talunays#gmail.com',
'talunays#gmail.com',
'talunays#gmail.com',
'talunays#gmail.com'
);
$total = count($mailExp);
for($i=0;$i<$total-1;$i++)
{
$workers[$i]=new workerThread($mailExp[$i]);
$workers[$i]->start();
}
But it doesn't work, duplicate lines still there and cannot be removed...
You should use construct only to set your private $this variables.
Make the logic inside the run function and use array_unique.
Let the workers come back with join() and retrieve the unduplicated arrays at this point.
safe storage of data. I read that for this task suits Stackable.
I inherit Stackable but data in storage is not synchronized.
AsyncOperation -- just incrementing value in storage
AsyncWatcher -- just making echo of value in storage.
Problem : data in storage is not modifying from AsyncOperation thread, storage permanently contains a -1.
I'm using pthreads.
class Storage extends Stackable {
public function __construct($data) {
$this->local = $data;
}
public function run()
{
}
public function getData() { return $this->local; }
}
class AsyncOperation extends Thread {
private $arg;
public function __construct(Storage $param){
$this->arg = $param->getData();
}
public function run(){
while (true) {
$this->arg++;
sleep(1);
}
}
}
class AsyncWatcher extends Thread {
public function __construct(Storage $param){
$this->storage = $param -> getData();
}
public function run(){
while (true) {
echo "In storage ". $this->storage ."\n";
sleep(1);
}
}
}
$storage = new Storage(-1);
$thread = new AsyncOperation($storage);
$thread->start();
$watcher = new AsyncWatcher($storage);
$watcher->start();
As you can see, Stackable class has a lot of methods, mainly used for async operations and they can help you with your issue. You should modify your async classes in this way:
class AsyncOperation extends Thread {
private $arg;
public function __construct(Storage $param){
$this->arg = $param->getData();
}
public function run(){
while (true) {
$this->arg++;
sleep(1);
}
$this->synchronized(function($thread){
$thread->notify();
}, $this);
}
}
and their usage will be like this:
$storage = new Storage();
$asyncOp = new AsyncOperation($storage);
$asyncOp->start();
$asyncOp->synchronized(function($thread){
$thread->wait();
}, $asyncOp);
var_dump($storage);
I am running 4 threads running in same time. (Threads are running work() function in same time in this case)
global $i;
$i = 1;
function work($address) {
while($i < 1000) {
$i++;
----
if($i == something) some job...
----
}
}
For some reason this don't do the job.
Threads do sometimes same circle in while, so I have later some duplicate values. (probably they have some critical section)
Any idea how to fix this ?
The counter object must be thread safe, it must also employ synchronized methods.
Follows is an example of such code:
<?php
class Counter extends Threaded {
public function __construct($value = 0) {
$this->value = $value;
}
/** protected methods are synchronized in pthreads **/
protected function increment() { return ++$this->value; }
protected function decrement() { return --$this->value; }
protected $value;
}
class My extends Thread {
/** all threads share the same counter dependency */
public function __construct(Counter $counter) {
$this->counter = $counter;
}
/** work will execute from job 1 to 1000, and no more, across all threads **/
public function run() {
while (($job = $this->counter->increment()) <= 1000) {
printf("Thread %lu doing job %d\n",
Thread::getCurrentThreadId(), $job);
}
}
protected $counter;
}
$counter = new Counter();
$threads = [];
while (($tid = count($threads)) < 4) {
$threads[$tid] = new My($counter);
$threads[$tid]->start();
}
foreach ($threads as $thread)
$thread->join();
?>
work() seems superfluous, this logic should be in the ::run function most likely.
<?php
class Timer {
static private $s;
function __construct()
{
self::$s = self::getmicrotime();
}
static public function Start()
{
self::$s = self::getmicrotime();
}
static public function Fetch($decimalPlaces = 6)
{
return number_format((self::getmicrotime() - self::$s), $decimalPlaces);
}
static public function getmicrotime()
{
return array_sum(explode(' ', microtime()));
}
}
class T extends Thread {
public function run() {
test();
}
}
function test()
{
$n = 0;
for($i=1;$i<9999999;$i++)
{
$n+=$i;
}
echo '#';
}
//+++++++++++++++++++++++START DEMO ++++++++++++++++++++++++++
Timer::Start();
//DEMO1,TIME:3.679208 second(s).
$ts = array();
while (count($ts)<10) {
$t = new T();
$t->start();
$ts[]=$t;
}
$ts = array();
//DEMO2,TIME:6.876037 second(s).
/* for($k=0;$k<10;$k++)
{
$t = new T();
$t->start();
} */
echo '<br />Processed in '.Timer::Fetch().' second(s).';
?>
I am reading http://pthreads.org/ on the topic of pthreads and i have this questions,I want to test php multithreading ,but when i use for to create multithreading,but it is not the result I want.
In fact the DEMO1 is correct.
But why the second DEMO elapsed_time 6.876037 second ?
DEMO2 why canot use for to create multithreading ?