0

I have problem with adding new element in array with pointers.

thread.php:

class Process extends Thread {

public function __construct(&$list )
{
    $this->list = $list;
}

public function run() { 

    while ((1000 <= count($this->list))) {
        print_r($list) // array("one", "two");
        listing($this->list);
        print_r($list) // still array("one", "two");
    }
}
}

index.php:

$links = array("one", "two");

function addNew(&$list)
{
    // some job
    array_push($list, "three");
    print_r($list) // array("one", "two","three");
}
function work(&$list)
{
     // some code...

        addNew($list);
}

$jobs = array(
    new Process($list),
    new Process($list),
    new Process($list)
);

foreach ($jobs as $job)
    $job->start();

Value of the links will be always only ("one","two") no matter how elements I add later in function addNew().

I need pointers cause this will be looping a lots of times with huge amount of elements and I don't want to create always new array.

Ivan Vulović
  • 2,147
  • 6
  • 27
  • 43
  • khm...first thing I see: `$this->list` doesnt exist, you miss `private $list;` –  Sep 17 '14 at 11:13
  • I am not a php expert, but I suspect `$this->list = $list;` makes a by-value copy, instead of getting a reference – thumbmunkeys Sep 17 '14 at 11:14
  • IMHO, threading and PHP don't mix, but that's just my opinion. However, using `__construct($list = null)` (making it optional), and assigning `$list`, if it was passed to the constructor to a `static` property makes it shared across all instances. PS: PHP doesn't _do_ pointers, it has references that are sort of like C pointers, but they're not the same thing. – Elias Van Ootegem Sep 17 '14 at 11:14
  • 1
    @thumbmunkeys: `$list` is a reference: `__construct(&$list)`, so assigning a reference is like having `void some_func(type *list) { type *some_var = list;}`, it's copy by value, but the value is a reference/pointer – Elias Van Ootegem Sep 17 '14 at 11:16
  • 1
    @thumbmunkeys: NP, but you do make a good point: assigning a reference to a property, especially when using threads is more complicated than that, check [array iteration by reference here](http://stackoverflow.com/a/14854568/1230836) and references that aren't threaded are copied, regardless [as explained here](http://stackoverflow.com/questions/14564234/pthread-thread-objects-reset-their-state) – Elias Van Ootegem Sep 17 '14 at 11:25
  • @EliasVanOotegem yea, but I really need threads, and if I do this with some stupid int variable and just increment (example $this->add = 0) after every $add++ in addNew function, number will increment like it should (permanently). I first though it was some problem with arrays. – Ivan Vulović Sep 17 '14 at 11:38
  • @IvanVulović: That's plausible, seeing as an array is a `HashTable` internally. Scalar values needn't be serialized, and get the `refcount` member set accordingly, and the copy-on-write way the Zend Engine works can explain why the int works, but the array doesn't. check the links in my previous comments, which give some more details on how PHP works internally – Elias Van Ootegem Sep 17 '14 at 11:43

1 Answers1

1

The reason you are not allowed to use references, even to types that do not require serialization, is that there would be no opportunity to provide safety if you were allowed to do that ...

Consider the following:

$this->member = $data;

Currently, this is an atomic write to the Threaded object, and this:

$data = $this->member;

an atomic read.

If these actions were not atomic, consider that if some other thread calls the first example of code while another thread is calling the second, $data would be garbage at best and generate a fault at worst.

Consider that if references were allowed and the following code worked:

$data =& $this->member;

The context with a reference to data would be allowed to break safety, with no opportunity to intervene, it would be extremely hard to program with threads in this way.

The beauty of a high level threading API is that you do not have to worry so much about safety, it is provided for you, don't seek out ways to break that safety has to be good advice.

All Threaded objects behave as if they are an array, with utility methods like pop and operators installed so that they can be treated as an array by your code.

Threaded objects are not serialized, they are safe, you still cannot use references, but nor do you need too:

<?php
class Shared extends Threaded {}

class Appender extends Thread {

    public function __construct(Shared $shared) {
        $this->shared = $shared;
    }

    public function run() {
        while (count($this->shared) < 1000) {
            $this->shared[] = 
                count($this->shared);
        }
    }

    protected $shared;
}

class Shifter extends Thread {

    public function __construct(Shared $shared) {
        $this->shared = $shared;
    }

    public function run() {
        while(count($this->shared)) {
            var_dump($this->shared->shift());
        }
    }
}

$shared   = new Shared();

$appender = new Appender($shared);
$shifter  = new Shifter($shared);

$appender->start();
$shifter->start();

$appender->join();
$shifter->join();
?>

The code above shares an object of class Shared between two other threads, as a simple example, one thread is pushing and another shifting from the same array, safely.

This example code isn't meant to be a good example of anything other than using Threaded objects as if they are arrays.

Joe Watkins
  • 17,032
  • 5
  • 41
  • 62