Nested locks / free calls in shared memory synchronization using semaphores

[EDIT] Finish rewriting with background added (original question below)

In a PHP application, I used shared memory to temporarily store values ​​for performance reasons (the database has too much overhead and the files are too slow).

I built a really simple shared memory class that gives scripts access to variables stored in shared memory and has the ability to synchronize calls using semaphores. Code here (no error handling):

class SHM {

    private static $defaultSize = 10000;

    private static function getIdentifier ($identFile, $projId) {
        return ftok($identFile, $projId);
    }

    private $sem = NULL;
    private $shm = NULL;
    private $identFile;
    private $projId;
    private $size;

    public function __construct($identFile, $projId, $size=NULL) {
        if ($size === NULL) $size = self::$defaultSize;
        $this->identFile = $identFile;
        $this->projId    = $projId;
        $this->size      = $size;
    }

    public function __destruct() {
        if ($this->sem) {
            $this->lock();
            if ($this->shm) {
                shm_detach($this->shm);
            }
            $this->free();
        }
    }

    public function exists ($key) {
        return shm_has_var($this->getShm(), $key);
    }

    public function get ($key, $lock=true) {
        if ($this->exists ($key)) {
            if ($lock) $this->lock();
            $var = shm_get_var($this->getShm(), $key);
            if ($lock) $this->free();
            return $var;
        } else return NULL;
    }

    public function set ($key, $var, $lock=true) {
        if ($lock) $this->lock();
        shm_put_var($this->getShm(), $key, $var);
        if ($lock) $this->free();
    }

    public function remove ($key, $lock=true) {
        if ($this->exists ($key)) {
            if ($lock) $this->lock();
            $result = shm_remove_var($this->getShm(), $key);
            if ($lock) $this->free();
            return $result;
        } else return NULL;
    }

    public function clean () {
        $this->lock();
        shm_remove($this->shm);
        $this->free();
        sem_remove($this->sem);
        $this->shm = NULL;
        $this->sem = NULL;
    }

    private function getSem () {
        if ($this->sem === NULL) {
            $this->sem = sem_get(self::getIdentifier($this->identFile, $this->projId));
        }
        return $this->sem;
    }

    private function lock () {
        return sem_acquire($this->getSem());
    }

    private function free () {
        return sem_release($this->getSem());
    }

    private function getShm () {
        if ($this->shm === NULL) {
            $this->shm = shm_attach(self::getIdentifier($this->identFile, $this->projId), $this->size);
        }
        return $this->shm;
    }
}

Now I have another class that uses this shared memory class and must perform the “get, modify and write” operation for one variable. Mainly:

function getModifyWrite () {
   $var = $mySHM->get('var');
   $var += 42;
   $mySHM->set('var', $var);
}

, , , , . , .

, sem_acquire sem_release. , ( @Ben), System V lock .

PHP ( ), , varialbes (, , ...) . , .

sugestions hwo , DRY-?

, System V PHP:

(sem_acquire) , ( (sem_release) , ), sem_acquire , , ( free )?

, , , ^^

:

$sem = sem_get(ftok('/some/file', 'a'));

function doSomething1 () {
     sem_acquire($sem);
     doSomething2();
     // do something else
     sem_release($sem);
}

function doSomething2 () {
     sem_acquire($sem);
     // do stuff
     sem_release($sem);
}

, doSomething1, sem_release doSomething2 "2" ( , sem_get), , ?

, , doSomething1 , . , , doSomething2, , . , doSomething2 , , , , . , , .

, , , , System V , , ( , free, lock).

+3
1

( - , , / , !):

1) lock unlock / , / , .

2) modify SHM, . , , ( - 1)), , ( : ) , .

modify : , ( ), modify() . .

SHM (- , free lock , ):

<?php namespace Utilities;

 //TODO: ERROR HANDLING

class SHM {

    private static function getIdentifier ($identFile, $projId) {
        return ftok($identFile, $projId);
    }

    private static $defaultSize = 10000;

    private $sem = NULL;
    private $shm = NULL;
    private $identFile;
    private $projId;
    private $size;
    private $locked=0;

    public function __construct($identFile, $projId, $size=NULL) {
        if ($size === NULL) $size = self::$defaultSize;
        $this->identFile = $identFile;
        $this->projId    = $projId;
        $this->size      = $size;
    }

    public function __destruct() {
        if ($this->sem) {
            $this->lock();
            if ($this->shm) {
                shm_detach($this->shm);
            }
            $this->free();
        }
    }

    public function clean () {
        $this->lock();
        shm_remove($this->shm);
        $this->free();
        sem_remove($this->sem);
        $this->shm = NULL;
        $this->sem = NULL;
    }

    public function __isset($key) {
        return $this->exists($key);
    }

    public function __get($key) {
        return $this->get($key);
    }

    public function __set($key, $val) {
        return $this->set($key, $val);
    }

    public function __unset($key) {
        return $this->remove($key);
    }

    public function exists ($key) {
        return shm_has_var($this->getShm(), $key);
    }

    public function get ($key, $lock=true) {
        if ($this->exists ($key)) {
            if ($lock) $this->lock();
            $var = shm_get_var($this->getShm(), $key);
            if ($lock) $this->free();
            return $var;
        } else return NULL;
    }

    public function set ($key, $var, $lock=true) {
        if ($lock) $this->lock();
        shm_put_var($this->getShm(), $key, $var);
        if ($lock) $this->free();
    }

    public function modify ($key, $action, $useReturn = false) {
        $var = $this->get($key);
        $result = $action($var);
        if ($useReturn) {
            $var = $result;
        }
        $this->set($key, $var);
    }

    public function remove ($key, $lock=true) {
        if ($this->exists ($key)) {
            if ($lock) $this->lock();
            $result = shm_remove_var($this->getShm(), $key);
            if ($lock) $this->free();
            return $result;
        } else return NULL;
    }

    private function getSem () {
        if ($this->sem === NULL) {
            $this->sem = sem_get(self::getIdentifier($this->identFile, $this->projId));
        }
        return $this->sem;
    }

    private function getShm () {
        if ($this->shm === NULL) {
            $this->shm = shm_attach(self::getIdentifier($this->identFile, $this->projId), $this->size);
        }
        return $this->shm;
    }

    private function lock () {
        if ($this->locked == 0) {
            $result = sem_acquire($this->getSem());
            if (!$result) return 0;
        }
        return ++$this->locked;
    }

    private function free () {
        if ($this->locked == 1) {
            $result = sem_release($this->getSem());
            if (!$result) return 0;
        }
        return --$this->locked;
    }

}
0

All Articles