< ?php // // +----------------------------------------------------------------------+ // | Copyright (c) 2006 Andrey Hristov | // +----------------------------------------------------------------------+ // | This source file is subject to version 3.0 of the PHP license, | // | and is available at through the world-wide-web at | // | http://www.php.net/license/3_0.txt | // | If you did not receive a copy of the PHP license and are unable to | // | obtain it through the world-wide-web, please send a note to | // | license@php.net so we can mail you a copy immediately. | // +----------------------------------------------------------------------+ // | Author: Andrey Hristov | // +----------------------------------------------------------------------+ // /* This is a class that implements a Read/Write Lock for PHP by using only semaphores. This code IS NOT TESTED at all. I wrote it because I was asked how it could be implemented. If you find bugs (you will probably) please contact me and I will update this file accordingly. This is put on WWW because one day I may decide to go back on IPC with PHP and test this piece of code. I am not 100% sure that the idea actually works :), but it should. If you are using PHP5 then replace "/ * PHP5 * / &" (remove the spaces) with empty string. Read/Write Locking : If there is(are) reader(s), the writers wait actually sleeping. I am using busy wait for this because SystemV IPC does not have equivalent of POSIX Threads' conditional variables. Therefore the effect could not be the same as with pthreads implementation (find an example of implementation in MySQL's sources mysys/thr_rwlock.c). 1. If there are writers, the reader will sleep and then check again. 2. If there are attempting writers, the reader will sleep and then check again. 3. If there are no writers or attempting to write processes the reader will increase the readers variable. 4. If there are readers, a writer will increase, only once, writers_waiting variable and sleep, then check again for readers. 5. If there are writers, a writer will increase, only once, writers_waiting variable and sleep, then check again for writers. Usage: script1.php: $lock= new SHM_RWLock("my_lock"); $lock->lockRead(); .... $lock->unlockRead(); script2.php: $lock= new SHM_RWLock("my_lock"); $lock->lockWrite(); .... $lock->unlockWrite(); Enjoy! */ class SHM_RWLock { var $semaphore; var $readers; var $writers; var $writers_waiting; var $wait_time; // in milliseconds 1 000 000 = 1s function __construct($name, $wait_time = 50000) { $this->semaphore= /*PHP5*/&new Shm_Semaphore($name); $this->wait_time= $wait_time; /* 100 should be enough for an int */ $this->readers= /*PHP5*/&new Shm_Var($name.'_readers', 100, '666'); $this->writers= /*PHP5*/&new Shm_Var($name.'_writers', 100, '666'); $this->writers= /*PHP5*/&new Shm_Var($name.'_waiting', 100, '666'); } function _increaseVar(/*PHP5*/&$var) { $var->putVar($var->getVar() + 1); } function _decreaseVar(/*PHP5*/&$var) { $var->putVar($var->getVar() - 1); } function lockRead() { do { $this->semaphore->acquire(); if ($this->writers || $this->writers_waiting) { $this->semaphore->release(); usleep($this->wait_time); continue; } else { _increaseVar($this->readers); $this->semaphore->release(); } } while (0); } function unlockRead() { $this->semaphore->acquire(); _decrease_var($this->readers); $this->semaphore->release(); } function lockWrite() { $increased= false; do { $this->semaphore->acquire(); if ($this->readers || $this->writers) { if (!$increased) { _increaseVar($this->writers_waiting); $increased= true; } $this->semaphore->release(); usleep($this->wait_time); continue; } else if (!$readers && !$writers) { _decrease_var($this->writers_waiting); _increaseVar($this->writers); $this->semaphore->release(); } } while (0); } function unlockWrite() { $this->semaphore->acquire(); _decrease_var($this->writers); $this->semaphore->release(); } } ? >