You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 line
3.4KB

  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;
  9. use yii\base\Component;
  10. /**
  11. * The Mutex component allows mutual execution of concurrent processes in order to prevent "race conditions".
  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 boolean 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 integer $timeout time 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 boolean lock acquiring result.
  62. */
  63. public function acquire($name, $timeout = 0)
  64. {
  65. if ($this->acquireLock($name, $timeout)) {
  66. $this->_locks[] = $name;
  67. return true;
  68. } else {
  69. return false;
  70. }
  71. }
  72. /**
  73. * Releases acquired lock. This method will return false in case the lock was not found.
  74. * @param string $name of the lock to be released. This lock must already exist.
  75. * @return boolean lock release result: false in case named lock was not found..
  76. */
  77. public function release($name)
  78. {
  79. if ($this->releaseLock($name)) {
  80. $index = array_search($name, $this->_locks);
  81. if ($index !== false) {
  82. unset($this->_locks[$index]);
  83. }
  84. return true;
  85. } else {
  86. return false;
  87. }
  88. }
  89. /**
  90. * This method should be extended by a concrete Mutex implementations. Acquires lock by name.
  91. * @param string $name of the lock to be acquired.
  92. * @param integer $timeout time to wait for the lock to be released.
  93. * @return boolean acquiring result.
  94. */
  95. abstract protected function acquireLock($name, $timeout = 0);
  96. /**
  97. * This method should be extended by a concrete Mutex implementations. Releases lock by given name.
  98. * @param string $name of the lock to be released.
  99. * @return boolean release result.
  100. */
  101. abstract protected function releaseLock($name);
  102. }