Mutex.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\mutex;
  8. use yii\base\Component;
  9. /**
  10. * The Mutex component allows mutual execution of concurrent processes in order to prevent "race conditions".
  11. * This is achieved by using a "lock" mechanism. Each possibly concurrent thread cooperates by acquiring
  12. * a lock before accessing the corresponding data.
  13. *
  14. * Usage example:
  15. *
  16. * ```
  17. * if ($mutex->acquire($mutexName)) {
  18. * // business logic execution
  19. * } else {
  20. * // execution is blocked!
  21. * }
  22. * ```
  23. *
  24. * This is a base class, which should be extended in order to implement the actual lock mechanism.
  25. *
  26. * @author resurtm <resurtm@gmail.com>
  27. * @since 2.0
  28. */
  29. abstract class Mutex extends Component
  30. {
  31. /**
  32. * @var bool whether all locks acquired in this process (i.e. local locks) must be released automatically
  33. * before finishing script execution. Defaults to true. Setting this property to true means that all locks
  34. * acquired in this process must be released (regardless of errors or exceptions).
  35. */
  36. public $autoRelease = true;
  37. /**
  38. * @var string[] names of the locks acquired by the current PHP process.
  39. */
  40. private $_locks = [];
  41. /**
  42. * Initializes the Mutex component.
  43. */
  44. public function init()
  45. {
  46. if ($this->autoRelease) {
  47. $locks = &$this->_locks;
  48. register_shutdown_function(function () use (&$locks) {
  49. foreach ($locks as $lock) {
  50. $this->release($lock);
  51. }
  52. });
  53. }
  54. }
  55. /**
  56. * Acquires a lock by name.
  57. * @param string $name of the lock to be acquired. Must be unique.
  58. * @param int $timeout time to wait for lock to be released. Defaults to zero meaning that method will return
  59. * false immediately in case lock was already acquired.
  60. * @return bool lock acquiring result.
  61. */
  62. public function acquire($name, $timeout = 0)
  63. {
  64. if ($this->acquireLock($name, $timeout)) {
  65. $this->_locks[] = $name;
  66. return true;
  67. } else {
  68. return false;
  69. }
  70. }
  71. /**
  72. * Releases acquired lock. This method will return false in case the lock was not found.
  73. * @param string $name of the lock to be released. This lock must already exist.
  74. * @return bool lock release result: false in case named lock was not found..
  75. */
  76. public function release($name)
  77. {
  78. if ($this->releaseLock($name)) {
  79. $index = array_search($name, $this->_locks);
  80. if ($index !== false) {
  81. unset($this->_locks[$index]);
  82. }
  83. return true;
  84. } else {
  85. return false;
  86. }
  87. }
  88. /**
  89. * This method should be extended by a concrete Mutex implementations. Acquires lock by name.
  90. * @param string $name of the lock to be acquired.
  91. * @param int $timeout time to wait for the lock to be released.
  92. * @return bool acquiring result.
  93. */
  94. abstract protected function acquireLock($name, $timeout = 0);
  95. /**
  96. * This method should be extended by a concrete Mutex implementations. Releases lock by given name.
  97. * @param string $name of the lock to be released.
  98. * @return bool release result.
  99. */
  100. abstract protected function releaseLock($name);
  101. }