Created
July 23, 2020 21:02
-
-
Save nevkontakte/e8f8e0fe631c51ad035c04394270698c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Simple mutex implementation | |
* | |
* This class implements sime kind of mutex using PHP's session file lock feature. | |
* To be short, PHP forces serial access for processes trying wokr with the same session file. | |
* This is the most simple mutex imitation (flock() is a strange function with unpredictable bugs), | |
* but this method has some disadvantages and limitations which you should be aware of: | |
* 1) Using such mutexes together with native PHP sessions can cause unexpected behaviour and possible | |
* session DATA LOSS! | |
* 2) It allows not more than one locked mutex at the same time, because only one active session may exist. | |
* 3) There are one known bug: when two parallel requests are handled by the same script and PHP runs as | |
* Apache's mod_php this requests will be executed in ENTIRELY SERIAL way, not only in block which are | |
* protected with mutex. I have no idea why does it happen. | |
* 4) This class works only if sessions are handled by native "files" module. | |
* So, this class should be used only in simple and small scripts. In large projects consider using | |
* something like semaphores module (http://en.php.net/manual/en/book.sem.php) | |
* | |
* @author Alek$ <aleks@aradmin.org.ru> http://nevkontakte.org.ru | |
* @license New BSD License (http://www.opensource.org/licenses/bsd-license.php) | |
*/ | |
class PHP_Mutex | |
{ | |
private static $mutex = null; | |
private $locked = false; | |
private $old_session = ""; | |
/** | |
* Lock mutex $id | |
* | |
* @param string $id Mutex name. | |
*/ | |
public static function lock($id) | |
{ | |
self::init(); | |
self::$mutex->getLock($id); | |
} | |
/** | |
* Unlock mutex $id. Note that it must be the same as used in previous lock() call. | |
* | |
* @param string $id Mutex name. | |
*/ | |
public static function unlock($id) | |
{ | |
self::init(); | |
self::$mutex->releaseLock($id); | |
} | |
private function __construct($man = false) | |
{ | |
if(session_module_name() !== "files") | |
{ | |
trigger_error('PHP_Mutex relies on "files" session handler module, but '.session_module_name().' is used', E_USER_WARNING); | |
} | |
if(session_id() !== "") | |
{ | |
trigger_error('Possible session conflict with PHP_Mutex: already started session detected', E_USER_WARNING); | |
$this->old_session = session_id(); | |
} | |
} | |
private function getLock($id) | |
{ | |
if($this->locked === true) | |
{ | |
trigger_error("Tried to lock mutex $id, but mutex ".session_id()." is already locked and only one locked mutex can exist at the same time", E_USER_ERROR); | |
} | |
$this->locked = true; | |
session_id($id); | |
session_start(); | |
} | |
private function releaseLock($id) | |
{ | |
if($this->locked == false) | |
{ | |
trigger_error("Mutex $id isn't locked", E_USER_WARNING); | |
return; | |
} | |
if($this->locked == true && $id !== session_id()) | |
{ | |
trigger_error("Tried to unlock mutex $id, but mutex ".session_id()." is currently locked", E_USER_WARNING); | |
return; | |
} | |
if($this->old_session !== "") | |
{ | |
session_id($this->old_session); | |
session_start(); | |
} | |
else | |
{ | |
session_destroy(); | |
session_write_close(); | |
flush(); | |
} | |
} | |
private static function init() | |
{ | |
if(self::$mutex == null) | |
{ | |
self::$mutex = new PHP_Mutex(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment