Mutex.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  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. *
  12. * This is achieved by using a "lock" mechanism. Each possibly concurrent thread cooperates by acquiring
  13. * a lock before accessing the corresponding data.
  14. *
  15. * Usage example:
  16. *
  17. * ```
  18. * if ($mutex->acquire($mutexName)) {
  19. * // business logic execution
  20. * } else {
  21. * // execution is blocked!
  22. * }
  23. * ```
  24. *
  25. * This is a base class, which should be extended in order to implement the actual lock mechanism.
  26. *
  27. * @author resurtm <resurtm@gmail.com>
  28. * @since 2.0
  29. */
  30. abstract class Mutex extends Component
  31. {
  32. /**
  33. * @var bool whether all locks acquired in this process (i.e. local locks) must be released automatically
  34. * before finishing script execution. Defaults to true. Setting this property to true means that all locks
  35. * acquired in this process must be released (regardless of errors or exceptions).
  36. */
  37. public $autoRelease = true;
  38. /**
  39. * @var string[] names of the locks acquired by the current PHP process.
  40. */
  41. private $_locks = [];
  42. /**
  43. * Initializes the Mutex component.
  44. */
  45. public function init()
  46. {
  47. if ($this->autoRelease) {
  48. $locks = &$this->_locks;
  49. register_shutdown_function(function () use (&$locks) {
  50. foreach ($locks as $lock) {
  51. $this->release($lock);
  52. }
  53. });
  54. }
  55. }
  56. /**
  57. * Acquires a lock by name.
  58. * @param string $name of the lock to be acquired. Must be unique.
  59. * @param int $timeout time (in seconds) to wait for lock to be released. Defaults to zero meaning that method will return
  60. * false immediately in case lock was already acquired.
  61. * @return bool lock acquiring result.
  62. */
  63. public function acquire($name, $timeout = 0)
  64. {
  65. if (!in_array($name, $this->_locks, true) && $this->acquireLock($name, $timeout)) {
  66. $this->_locks[] = $name;
  67. return true;
  68. }
  69. return false;
  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. }
  85. return false;
  86. }
  87. /**
  88. * This method should be extended by a concrete Mutex implementations. Acquires lock by name.
  89. * @param string $name of the lock to be acquired.
  90. * @param int $timeout time (in seconds) to wait for the lock to be released.
  91. * @return bool acquiring result.
  92. */
  93. abstract protected function acquireLock($name, $timeout = 0);
  94. /**
  95. * This method should be extended by a concrete Mutex implementations. Releases lock by given name.
  96. * @param string $name of the lock to be released.
  97. * @return bool release result.
  98. */
  99. abstract protected function releaseLock($name);
  100. }