Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to share global variable across thread in php?

In multithreading the global variables or resources are shared among threads. I'm using pthread library in c

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

void *worker(void *);

int ctr = 0;
pthread_mutex_t lock;

int main(int argc, char *argv[])
{
  pthread_t t[2];
  int i = 0;

//~ pthread_mutex_init(&lock, NULL);

  while(i < 2)
  {
     pthread_create(&t[i], NULL, &worker, NULL);
     i++;
  }

  pthread_join(t[0], NULL);
  pthread_join(t[1], NULL);

//~ pthread_mutex_destroy(&lock);
//~ pthread_join(t[1], NULL);
  return 0;
}

void *worker(void *arg)
{
//~ pthread_mutex_lock(&lock);
//~ int ctr = 0;
    ctr += 1;

    printf("job %d started\n", ctr);
    sleep(1);
//~ ctr += 1;
    printf("job %d finished\n", ctr);

//~ pthread_mutex_unlock(&lock);
}

This code output :

job 1 started
job 2 started
job 2 finished
job 2 finished

In this code the variable ctr are shared among thread, and therefore change made by other thread to that variable is visible to another thread (unless a call to some mutexes is done).

I'm tried that in php but no luck (using php pthreads). This is my php code :

global $ctr;

Class WorkerThread extends Worker
{
    private $thread_id;
    //~ public static $ctr = 0;
    private $mutext;

public function WorkerThread($mutex = NULL)
{ 
    //~ $this->ctr = $ctr;
    $this->mutex = $mutex;
    $this->start();
}

public function run()
{
    //~ Mutex::lock($this->mutex);
    $new_line = php_sapi_name() == "cli" ? PHP_EOL : "<br>";
    //~ global $ctr;
    $ctr = 0;
    $ctr += 1;
    echo "Thread " . $ctr . " started" . " [ " . $this->getThreadId() . " ]" . $new_line;
    sleep(1);
    echo "Thread " . $ctr . " Finished" . " [ " . $this->getThreadId() . " ]" . $new_line;
    //~ var_dump($this);
    //~ Mutex::unlock($this->mutex);
 }
}

//~ $mutex = Mutex::create();
$i = 0;
$worker = array();

while($i < 2)
{
   $worker[$i] = new WorkerThread();
//~ $worker[$i]->start();
   $i++;
}

foreach(range(0, 1) as $t)
   $worker[$t]->join();

//~ Mutex::destroy($mutex);

Output of this code :

Thread 1 started [ -1257948352 ]
Thread 1 started [ -1267893440 ]
Thread 1 Finished [ -1257948352 ]
Thread 1 Finished [ -1267893440 ]

the variable ctr(global) not updated by the thread like the c code above?

How to do that in php (sharing resources across threads)?

like image 896
Lundu Harianja Avatar asked Dec 24 '22 09:12

Lundu Harianja


1 Answers

Ordinarily, threads are executed in the same address space as the process that started them.

So, in C, the new threads are able to directly access variables on the stack of the main program.

When you create a new thread in PHP, it has a separate heap, it must execute in a separate address space.

This means that by default, you cannot share global state between threads.

This is the normal threading model of PHP - Share Nothing.

What pthreads does is introduce objects which are able to be manipulated in many contexts, and are able to share data among those contexts.

The equivalent PHP code might look something like:

<?php
class Atomic extends Threaded {

    public function __construct($value = 0) {
        $this->value = $value;
    }

    public function inc() {
        return $this->value++;
    }

    /* ... */
    private $value;
}

class Test extends Thread {

    public function __construct(Atomic $atomic) {
        $this->atomic = $atomic;
    }

    public function run() {
        $this->atomic->inc();
    }

    private $atomic;
}

$atomic = new Atomic();
$threads = [];

for ($thread = 0; $thread < 2; $thread++) {
    $threads[$thread] = new Test($atomic);
    $threads[$thread]->start();
}

foreach ($threads as $thread)
    $thread->join();

var_dump($atomic);
?>

Notice that, Mutex is not used directly (and has been removed from the latest versions of pthreads). Using Mutex is dangerous because you do not have enough control over execution to use them safely; If you lock a mutex and then for whatever reason the interpreter suffers a fatal error, you will not be able to release the mutex, deadlocks will follow ...

Nor is it necessary because single instruction operations on the object scope are atomic.

When it comes to implementing exclusion, you can use the Threaded::synchronized API to great effect.

Where exclusion is required, the run method might look more like:

    public function run() {
        $this->atomic->synchronized(function($atomic){
            /* exclusive */
            $atomic->inc();
        }, $this->atomic);
    }

Finally, a lesson in naming things ...

You appear to be, and are forgiven for being under the impression that, there is some parallel to be drawn between Posix Threads (the standard, pthread) and pthreads, the PHP extension ...

pthreads, the PHP extension happens to use Posix Threads, but it doesn't implement anything like Posix Threads.

The name pthreads should be taken to mean PHP threads ... naming things is hard.

like image 183
Joe Watkins Avatar answered Dec 28 '22 11:12

Joe Watkins