ID: 49010 User updated by: benjamin at josefus dot net Reported By: benjamin at josefus dot net Status: Bogus Bug Type: SPL related Operating System: Ubuntu 9.04, Kernel2.6.27 PHP Version: 5.3SVN-2009-07-21 (snap) New Comment:
I know that after a fork 2 processes work on their very own memory space. in fact, they work with two different objects. But then, why is the object hash the same for both Object Copies in concurrent Task::run() when spl_object_hash() is called (at least once) BEFORE fork? I mean, this is a quite curious behavior, don't you think? Previous Comments: ------------------------------------------------------------------------ [2009-07-22 12:12:17] il...@php.net Thank you for taking the time to write to us, but this is not a bug. Please double-check the documentation available at http://www.php.net/manual/ and the instructions on how to report a bug at http://bugs.php.net/how-to-report.php Forks are not threads, memory is not shared, so you end up with 2 copies of the executor, hence repetitive object ids. ------------------------------------------------------------------------ [2009-07-22 10:39:04] benjamin at josefus dot net In fact, there ain't no single word defining that spl_object_hash() should work in forked environments. For sure! But if an instance of class "Foo" is created BEFORE forking, shouldn't the object's ID be the same, in both forked and parent processes? Therefore, I expected the unique ID to be created for an object on contruct-Time. But this is not happening. It will be assigned at first time calling spl_object_hash() for an object. This is quite unsafe in distributed and concurrent enviroments. A simple functional example below: --------------------------------- class SharedObject { public function __construct($callSplObjectHash = false) { if ($callSplObjectHash) spl_object_hash($this); } } abstract class Task { protected $_pid; protected $_isChild; public function __construct() { $this->_isChild = false; } /** * Starts this Task running */ public function start() { // try to fork and acquire PID try { $pid = pcntl_fork(); if ($pid === 0) { // in chid process self::sleep(10); // sleep and release CPU after Fork $this->_isChild = true; $this->run(); // starts the logic routine exit(); } else if ($pid){ // in parent process $this->_pid = $pid; $this->_isChild = false; } else { throw new Excpetion('Could not do pcntl_fork(). Negative Return Value'); } } catch (Exception $e) { throw new Exception('Unable to Start Task. Cause: ' . $e->getMessage()); } } public static function sleep($millisecs) { usleep($millisecs * 1000); } abstract protected function run(); } class Producer extends Task { /** * @var SharedObject */ protected $o; public function __construct(SharedObject $o) { $this->o = $o; } protected function run() { echo 'Producer::run() ' . spl_object_hash($this->o) . PHP_EOL; } } class Worker extends Task { /** * @var SharedObject */ protected $o; public function __construct(SharedObject $o) { $this->o = $o; } protected function run() { echo 'Worker::run() ' . spl_object_hash($this->o) . PHP_EOL; } } // without spl_object_hash() called in Constructor $s = new SharedObject(); $p = new Producer($s); $w = new Worker($s); $w->start(); $p->start(); // with spl_object_hash() called in Constructor $s = new SharedObject(true); $p = new Producer($s); $w = new Worker($s); $w->start(); $p->start();) ------------------------------------------------------------------------ [2009-07-21 22:13:04] j...@php.net Where does it say that this function returns unique hash for objects run from forked PHP instances? And if you claim it should, provide a short but complete(!) reproducing script.. ------------------------------------------------------------------------ [2009-07-21 21:12:13] benjamin at josefus dot net This is the result with spl_object_hash() invoked first off (as it should be): not yet shared, initialize SHM 0000000016c4f93000000000506bf64a Worker: --> Wait!, ID: 0000000016c4f93000000000506bf64a Producer: --> Producing 0, ID: 0000000016c4f93000000000506bf64a Worker: --> Working on 0, ID: 0000000016c4f93000000000506bf64a Producer: --> Producing 1, ID: 0000000016c4f93000000000506bf64a Worker: --> Working on 1, ID: 0000000016c4f93000000000506bf64a Producer: --> Producing 2, ID: 0000000016c4f93000000000506bf64a Worker: --> Working on 2, ID: 0000000016c4f93000000000506bf64a Producer: --> Producing 3, ID: 0000000016c4f93000000000506bf64a Worker: --> Working on 3, ID: 0000000016c4f93000000000506bf64a Producer: --> Producing 4, ID: 0000000016c4f93000000000506bf64a Worker: --> Working on 4, ID: 0000000016c4f93000000000506bf64a Worker: --> Wait!, ID: 0000000016c4f93000000000506bf64a Producer: --> Producing 5, ID: 0000000016c4f93000000000506bf64a Worker: --> Working on 5, ID: 0000000016c4f93000000000506bf64a Producer: --> Producing 6, ID: 0000000016c4f93000000000506bf64a Worker: --> Working on 6, ID: 0000000016c4f93000000000506bf64a Producer: --> Producing 7, ID: 0000000016c4f93000000000506bf64a Worker: --> Working on 7, ID: 0000000016c4f93000000000506bf64a Producer: --> Producing 8, ID: 0000000016c4f93000000000506bf64a Worker: --> Working on 8, ID: 0000000016c4f93000000000506bf64a Producer: --> Producing 9, ID: 0000000016c4f93000000000506bf64a Worker: --> Working on 9, ID: 0000000016c4f93000000000506bf64a This one happens when spl_object_hash() has not been invoked first off: not yet shared, initialize SHM 0000000051f9a9a50000000056018292 not yet shared, initialize SHM 00000000187ccfd60000000067032181 Worker: --> Wait!, ID: 00000000187ccfd60000000067032181 Producer: --> Producing 0, ID: 0000000051f9a9a50000000056018292 Worker: --> Wait!, ID: 00000000187ccfd60000000067032181 Producer: --> Producing 1, ID: 0000000051f9a9a50000000056018292 Worker: --> Wait!, ID: 00000000187ccfd60000000067032181 Producer: --> Producing 2, ID: 0000000051f9a9a50000000056018292 Worker: --> Wait!, ID: 00000000187ccfd60000000067032181 Producer: --> Producing 3, ID: 0000000051f9a9a50000000056018292 Worker: --> Wait!, ID: 00000000187ccfd60000000067032181 Producer: --> Producing 4, ID: 0000000051f9a9a50000000056018292 Worker: --> Wait!, ID: 00000000187ccfd60000000067032181 Producer: --> Producing 5, ID: 0000000051f9a9a50000000056018292 Worker: --> Wait!, ID: 00000000187ccfd60000000067032181 Worker: --> Wait!, ID: 00000000187ccfd60000000067032181 Producer: --> Producing 6, ID: 0000000051f9a9a50000000056018292 Worker: --> Wait!, ID: 00000000187ccfd60000000067032181 Producer: --> Producing 7, ID: 0000000051f9a9a50000000056018292 Worker: --> Wait!, ID: 00000000187ccfd60000000067032181 Producer: --> Producing 8, ID: 0000000051f9a9a50000000056018292 Producer: --> Producing 9, ID: 0000000051f9a9a50000000056018292) ------------------------------------------------------------------------ [2009-07-21 20:54:56] benjamin at josefus dot net Description: ------------ I am working on a Task Management (java-like Threads) where each Task implements a pcntl_fork(), which works with shared Objects using IPC and Semaphore to access concurrently and synchronized. The Synchronisation should happen by unique Key per Object and SHM Segment (delivered by spl_object_hash). I am using sem_acquire(), sem_release(), shm_attach(), shm_release(), shm_[put|get]_var() and so on. When providing two concurrent Tasks with the same Object to be shared, spl_object_hash delivers two different Hashes, when invoked in each Task. Interestingly, if i call spl_object_hash for the shared Object before it is assigned to both "Producer" and "Worker" Task, the Hash IS unique, as it should be! In short: - new Object - fork -> spl_object_hash(Object) is NOT unique - new Object - call spl_object_hash(Object) first off - fork -> spl_object_hash(Object) IS unique and correct System Notes: PHP 5.3.0 (cli) (built: Jul 21 2009 22:19:17) Configure Command './configure' '--enable-pcntl' '--enable-shmop' '--enable-sysvmsg' '--enable-sysvsem' '--enable-sysvshm' '--with-apxs2=/usr/bin/apxs2' '--disable-short-tags' '--with-openssl' '--with-zlib' '--enable-bcmath' '--with-bz2=/bin/bzip2' '--enable-calendar' '--with-curl' '--with-curlwrappers' '--enable-exif' '--enable-ftp' '--with-gd' '--with-jpeg-dir=/usr/lib' '--with-png-dir=/usr/lib' '--with-xpm-dir=/usr/lib' '--with-t1lib' '--enable-gd-native-ttf' '--enable-gd-jis-conv' '--with-gettext' '--with-imap' '--with-imap-ssl' '--with-ldap' '--with-ldap-sasl' '--enable-mbstring' '--with-mcrypt' '--with-mhash' '--with-mysql=mysqlnd' '--with-mysqli=mysqlnd' '--with-pdo-mysql' '--with-pspell' '--with-readline' '--with-snmp' '--enable-soap' '--enable-sockets' '--without-sqlite' '--enable-sqlite-utf8' '--with-tidy' '--enable-wddx' '--with-xmlrpc' '--with-xsl' '--enable-zip' '--with-pear' '--with-kerberos' '--with-pgsql' '--with-pdo-pgsql' Reproduce code: --------------- $shared = new MySharedObj(); spl_object_hash($shared); //toggle this line to for in/correct result /** * $shared is referenced member variable in each task */ $producer = new ProducerTask($shared); $worker = new WorkerTask($shared); $producer->start(); $worker->start(); //outputs different Hash for $shared provided by spl_object_hash ------------------------------------------------------------------------ -- Edit this bug report at http://bugs.php.net/?id=49010&edit=1