Code snippets for symfony 1.x

Navigation

Refine Tags

Snippets tagged "mutex"

Mutex - Mutual exclusion semaphore

Sometimes you need mutual exclusion in an action. Imagine you are decreassing a stock number:

stock = 10;
user a ->  $itemX->getstock()   [10]
user b ->  $itemX->getstock()   [10]
user a -> $itemX->setStock(10-buyedItems)  [10-10=0]
user b -> $itemX->setStock(10-buyedItems)  [10-6=4]
user a-> $itemX->save()
user b -> $itemX->save()

The result will be an stock of 4, when it should be impossible to process the second transaction because no more stock is available....

The solution is to use Mutual exvlusion, here is a class that implements semaphores

<?php
 
    class Mutex
    {
        private $id;
        private $sem_id;
        private $is_acquired = false;
        private $is_windows = false;
        private $filename = '';
        private $filepointer;
 
        function __construct()
        {
            if(substr(PHP_OS, 0, 3) == 'WIN')
                $this->is_windows = true;
        }
 
        public function init($id, $filename = '')
        {
            $this->id = $id;
 
            if($this->is_windows)
            {
                if(empty($filename)){
                    throw new sfException(sprintf('nxMutex: no filename specified'));
                    return false;
                }
                else
                    $this->filename = $filename;
            }
            else
            {
                if(!($this->sem_id = sem_get($this->id, 1))){
                    throw new sfException(sprintf('nxMutex: Error getting semaphore'));
                    return false;
                }
            }
 
            return true;
        }
 
        public function acquire()
        {
            if($this->is_windows)
            {
                if(($this->filepointer = @fopen($this->filename, "w+")) == false)
                {
                    throw new sfException(sprintf('nxMutex: error opening mutex file'));
                    return false;
                }
 
                if(flock($this->filepointer, LOCK_EX) == false)
                {
                    throw new sfException(sprintf('nxMutex: error locking mutex file'));
                    return false;
                }
            }
            else
            {
                if (! sem_acquire($this->sem_id)){
                    throw new sfException(sprintf('nxMutex: error acquiring semaphore'));
                    return false;
                }
            }
 
            $this->is_acquired = true;
            return true;
        }
 
        public function release()
        {
            if(!$this->is_acquired)
                return true;
 
            if($this->is_windows)
            {
                if(flock($this->filepointer, LOCK_UN) == false)
                {
                    throw new sfException(sprintf('nxMutex: error unlocking mutex file'));
                    return false;
                }
 
                fclose($this->filepointer);
            }
            else
            {
                if (! sem_release($this->sem_id)){
                    throw new sfException(sprintf('nxMutex: error releasing semaphore'));
                    return false;
                }
            }
 
            $this->is_acquired = false;
            return true;
        }
 
        public function getId()
        {
            return $this->sem_id;
        }
    }
 
?>

the usage would be something like

$mutex=new Mutex();
$mutex->init(1,'mutexStock.txt');
$mutex->acquire();
$object->setStockobject->getStock()-$qtty);
$this->save();
$mutex->release();

bare in mind that the mutual exclusion will be based on the name passed on init function, so for mutual exclusion in diferent object you should concat the id of the object on the id of the muttex to avoid performance loose.

by Oriol Mercade on 2007-06-01, tagged exclusion  mutex  mutual  propel  semaphore