Semaphore.php 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: Jenner
  5. * Date: 2015/8/12
  6. * Time: 20:52
  7. */
  8. namespace Jenner\SimpleFork\Lock;
  9. /**
  10. * sem lock
  11. *
  12. * @package Jenner\SimpleFork\Lock
  13. */
  14. class Semaphore implements LockInterface
  15. {
  16. /**
  17. * @var
  18. */
  19. private $lock_id;
  20. /**
  21. * @var bool
  22. */
  23. private $locked = false;
  24. /**
  25. * init a lock
  26. *
  27. * @param $key
  28. * @param $count
  29. * @throws \RuntimeException
  30. */
  31. private function __construct($key, $count = 1)
  32. {
  33. if (($this->lock_id = sem_get($this->_stringToSemKey($key), $count)) === false) {
  34. throw new \RuntimeException("Cannot create semaphore for key: {$key}");
  35. }
  36. }
  37. /**
  38. * Semaphore requires a numeric value as the key
  39. *
  40. * @param $identifier
  41. * @return int
  42. */
  43. protected function _stringToSemKey($identifier)
  44. {
  45. $md5 = md5($identifier);
  46. $key = 0;
  47. for ($i = 0; $i < 32; $i++) {
  48. $key += ord($md5{$i}) * $i;
  49. }
  50. return $key;
  51. }
  52. /**
  53. * create a lock instance
  54. *
  55. * @param $key
  56. * @return Semaphore
  57. */
  58. public static function create($key)
  59. {
  60. return new Semaphore($key);
  61. }
  62. /**
  63. * release lock
  64. *
  65. * @throws \RuntimeException
  66. */
  67. public function __destruct()
  68. {
  69. if ($this->isLocked()) {
  70. $this->release();
  71. }
  72. }
  73. /**
  74. * is locked
  75. *
  76. * @return bool
  77. */
  78. public function isLocked()
  79. {
  80. return $this->locked === true ? true : false;
  81. }
  82. /**
  83. * release lock
  84. *
  85. * @return bool
  86. * @throws \RuntimeException
  87. */
  88. public function release()
  89. {
  90. if (!$this->locked) {
  91. throw new \RuntimeException("release a non lock");
  92. }
  93. if (!sem_release($this->lock_id)) {
  94. return false;
  95. }
  96. $this->locked = false;
  97. return true;
  98. }
  99. /**
  100. * get a lock
  101. *
  102. * @param bool $blocking
  103. * @return bool
  104. */
  105. public function acquire($blocking = true)
  106. {
  107. if ($this->locked) {
  108. throw new \RuntimeException('already lock by yourself');
  109. }
  110. if ($blocking === false) {
  111. if (version_compare(PHP_VERSION, '5.6.0') < 0) {
  112. throw new \RuntimeException('php version is at least 5.6.0 for param blocking');
  113. }
  114. if (!sem_acquire($this->lock_id, true)) {
  115. return false;
  116. }
  117. $this->locked = true;
  118. return true;
  119. }
  120. if (!sem_acquire($this->lock_id)) {
  121. return false;
  122. }
  123. $this->locked = true;
  124. return true;
  125. }
  126. /**
  127. * remove the semaphore resource
  128. *
  129. * @return bool
  130. */
  131. public function remove()
  132. {
  133. if ($this->locked) {
  134. throw new \RuntimeException('can not remove a locked semaphore resource');
  135. }
  136. if (!is_resource($this->lock_id)) {
  137. throw new \RuntimeException('can not remove a empty semaphore resource');
  138. }
  139. if (!sem_release($this->lock_id)) {
  140. return false;
  141. }
  142. return true;
  143. }
  144. }