+ -
当前位置:首页 → 问答吧 → 使用共享内存实现php Spinlock

使用共享内存实现php Spinlock

时间:2011-07-15

来源:互联网

本文使用共享内存方式实现一个属于php的“自旋锁(Spinlock)”。
主要特点:
1、检测和避免死锁
2、并可以自定义锁定超时
3、可以在运行结束后自动释放锁定
4、可搜集分析锁竞争和锁等待情况
  1. <?php
  2. /**
  3. * php"自旋锁"功能 (PHP Spinlocks)
  4. * 用于php进程同步时使用
  5. *
  6. * Author : lajabs.net 2011/7/15
  7. */

  8. class slock
  9. {
  10.         /**
  11.          * $lock_timeout 设置等待回旋次数
  12.          * $lock_wait_func 设置等待机制,本例使用usleep+mt_rand随机等待,随机等待有利错开多个竞争
  13.          * $add_func 这里设置添加锁标志机制,本例使用PHP的APC组件apc_add函数,apc_add设定锁占有上限为5s,避免永久占有
  14.          * $del_func 这里设置删除锁标志机制,本例使用PHP的APC组件apc_delete函数
  15.          */
  16.         private $locks;
  17.         private $lock_timeout = 200;
  18.         private $lock_wait_func;
  19.         private $add_func;
  20.         private $del_func;
  21.         public function __construct()
  22.         {
  23.                 $this->add_func = function($mutex)
  24.                 {
  25.                         return apc_add('sl:'.$mutex,1,5);
  26.                 };

  27.                 $this->del_func = function($mutex)
  28.                 {
  29.                         return apc_delete('sl:'.$mutex);
  30.                 };

  31.                 $this->lock_wait_func = function()
  32.                 {
  33.                         usleep(mt_rand(10000,50000));
  34.                 };
  35.         }

  36.         public function __destruct()
  37.         {
  38.                 $this->clean();
  39.         }
  40.        



  41.         /*================================= 分割线 ==========================*/



  42.         /**
  43.          * 清除当前所有设置的锁,在当前的php进程中可以设置多个锁
  44.          */
  45.         public function clean()
  46.         {
  47.                 if($this->locks)
  48.                 {
  49.                         foreach($this->locks as $lock => $tmp)
  50.                                 call_user_func($this->del_func ,$lock);
  51.                         $this->locks = null;
  52.                 }
  53.         }



  54.         /**
  55.          * 新建立一个锁
  56.          * 首先会判断锁定标志是否已经定义,如果已锁定则判定为死锁
  57.          * 其次使用apc共享内存方式add一个锁标志,如果失败则进入等待时间,直到超时
  58.          */
  59.         public function lock($mutex)
  60.         {
  61.                 if($this->locks[$mutex]!=null)
  62.                 {
  63.                         throw new Exception('Detected deadlock.');
  64.                         return false;
  65.                 }

  66.                 while(call_user_func($this->add_func ,$mutex) == false)
  67.                 {
  68.                         ++$i;
  69.                         if($i > $this->lock_timeout)
  70.                         {
  71.                                 throw new Exception('lock timeout.');
  72.                                 return false;
  73.                         }
  74.                         call_user_func($this->lock_wait_func);
  75.                 }
  76.                 $this->locks[$mutex] = 1;
  77.                 return $mutex;
  78.         }


  79.         /**
  80.          * 手动释放锁,一般不用,
  81.          * 在当前对象析构时会自动释放所有锁
  82.          */
  83.         public function release($mutex)
  84.         {
  85.                 if($mutex == false) return false;
  86.                 unset($this->locks[$mutex]);
  87.                 call_user_func($this->del_func ,$mutex);
  88.                 return true;
  89.         }
  90. }


  91. /*
  92. Example:

  93. $lock = new slock();
  94. echo 'Start:',date('H:m:s'),',';
  95. $lock->lock(123);
  96. sleep(3);
  97. echo 'Stop:',date('H:m:s');
  98. //$lock->release(123);
  99. */
  100. ?>
复制代码
运行上述例子,测试同步情况:
在两个浏览器打开运行这个代码,分别输出,
浏览器1:
Start:13:07:19,Stop:13:07:22
浏览器2:
Start:13:07:19,Stop:13:07:25

第一个浏览器显示程序运行了3秒后结束。
第二个浏览器等待3秒后开始运行,总共耗时6秒,测试通过。

作者: bs   发布时间: 2011-07-15

作者: iap_spring   发布时间: 2011-07-15

apc没办法支持分布式吧,意义不太大,直接memcached

作者: lkm1107   发布时间: 2011-07-15

apc没办法支持分布式吧,意义不太大,直接memcached
lkm1107 发表于 2011-7-15 16:34



适应重口味的,换成memcache端,改三行代码
  1.        
  2. ...
  3. public function __construct()
  4. {
  5.         $memcache_obj = memcache_connect("localhost", 11211);
  6.         $this->add_func = function($mutex) use ($memcache_obj)
  7.         {
  8.                 return memcache_add($memcache_obj, 'sl:'.$mutex, 1, false, 5);
  9.                 //return apc_add('sl:'.$mutex,1,5);
  10.         };

  11.         $this->del_func = function($mutex) use ($memcache_obj)
  12.         {
  13.                 return memcache_delete($memcache_obj, 'sl:'.$mutex);  //return apc_delete('sl:'.$mutex);
  14.         };

  15.         $this->lock_wait_func = function()
  16.         {
  17.                 usleep(mt_rand(10000,50000));
  18.         };
  19. }
  20. ...
复制代码

作者: bs   发布时间: 2011-07-15