- 论坛徽章:
- 0
|
本文使用共享内存方式实现一个属于php的“自旋锁(Spinlock)”。
主要特点:
1、检测和避免死锁
2、并可以自定义锁定超时
3、可以在运行结束后自动释放锁定
4、可搜集分析锁竞争和锁等待情况
- <?php
- /**
- * php"自旋锁"功能 (PHP Spinlocks)
- * 用于php进程同步时使用
- *
- * Author : lajabs.net 2011/7/15
- */
- class slock
- {
- /**
- * $lock_timeout 设置等待回旋次数
- * $lock_wait_func 设置等待机制,本例使用usleep+mt_rand随机等待,随机等待有利错开多个竞争
- * $add_func 这里设置添加锁标志机制,本例使用PHP的APC组件apc_add函数,apc_add设定锁占有上限为5s,避免永久占有
- * $del_func 这里设置删除锁标志机制,本例使用PHP的APC组件apc_delete函数
- */
- private $locks;
- private $lock_timeout = 200;
- private $lock_wait_func;
- private $add_func;
- private $del_func;
- public function __construct()
- {
- $this->add_func = function($mutex)
- {
- return apc_add('sl:'.$mutex,1,5);
- };
- $this->del_func = function($mutex)
- {
- return apc_delete('sl:'.$mutex);
- };
- $this->lock_wait_func = function()
- {
- usleep(mt_rand(10000,50000));
- };
- }
- public function __destruct()
- {
- $this->clean();
- }
-
- /*================================= 分割线 ==========================*/
- /**
- * 清除当前所有设置的锁,在当前的php进程中可以设置多个锁
- */
- public function clean()
- {
- if($this->locks)
- {
- foreach($this->locks as $lock => $tmp)
- call_user_func($this->del_func ,$lock);
- $this->locks = null;
- }
- }
- /**
- * 新建立一个锁
- * 首先会判断锁定标志是否已经定义,如果已锁定则判定为死锁
- * 其次使用apc共享内存方式add一个锁标志,如果失败则进入等待时间,直到超时
- */
- public function lock($mutex)
- {
- if($this->locks[$mutex]!=null)
- {
- throw new Exception('Detected deadlock.');
- return false;
- }
- while(call_user_func($this->add_func ,$mutex) == false)
- {
- ++$i;
- if($i > $this->lock_timeout)
- {
- throw new Exception('lock timeout.');
- return false;
- }
- call_user_func($this->lock_wait_func);
- }
- $this->locks[$mutex] = 1;
- return $mutex;
- }
- /**
- * 手动释放锁,一般不用,
- * 在当前对象析构时会自动释放所有锁
- */
- public function release($mutex)
- {
- if($mutex == false) return false;
- unset($this->locks[$mutex]);
- call_user_func($this->del_func ,$mutex);
- return true;
- }
- }
- /*
- Example:
- $lock = new slock();
- echo 'Start:',date('H:m:s'),',';
- $lock->lock(123);
- sleep(3);
- echo 'Stop:',date('H:m:s');
- //$lock->release(123);
- */
- ?>
复制代码 运行上述例子,测试同步情况:
在两个浏览器打开运行这个代码,分别输出,
浏览器1:
Start:13:07:19,Stop:13:07:22
浏览器2:
Start:13:07:19,Stop:13:07:25
第一个浏览器显示程序运行了3秒后结束。
第二个浏览器等待3秒后开始运行,总共耗时6秒,测试通过。 |
|