
<?php
/**
* 基于redis的分布式锁
*
* 参考开源代码:
* http://nleach.com/post/31299575840/redis-mutex-in-php
*
* https://gist.github.com/nickyleach/3694555
*/
pc_base::load_sys_class('cache_redis', '', 0); class dist_key_redis { //锁的超时时间
const TIMEOUT = 20; const SLEEP = 100000; /**
* Stores the expire time of the currently held lock
* 当前锁的过期时间
* @var int
*/
protected static $expire; public static function getRedis()
{
return new cache_redis();
} /**
* Gets a lock or waits for it to become available
* 获得锁,如果锁被占用,阻塞,直到获得锁或者超时
*
* 如果$timeout参数为0,则立即返回锁。
*
* @param string $key
* @param int $timeout Time to wait for the key (seconds)
* @return boolean 成功,true;失败,false
*/
public static function lock($key, $timeout = null){
if(!$key)
{
return false;
} $start = time(); $redis = self::getRedis(); do{
self::$expire = self::timeout(); if($acquired = ($redis->setnx("Lock:{$key}", self::$expire)))
{
break;
} if($acquired = (self::recover($key)))
{
break;
}
if($timeout === 0)
{
//如果超时时间为0,即为
break;
} usleep(self::SLEEP); } while(!is_numeric($timeout) || time() < $start + $timeout); if(!$acquired)
{
//超时
return false;
} return true;
} /**
* Releases the lock
* 释放锁
* @param mixed $key Item to lock
* @throws LockException If the key is invalid
*/
public static function release($key){
if(!$key)
{
return false;
} $redis = self::getRedis(); // Only release the lock if it hasn't expired
if(self::$expire > time())
{
$redis->del("Lock:{$key}");
}
} /**
* Generates an expire time based on the current time
* @return int timeout
*/
protected static function timeout(){
return (int) (time() + self::TIMEOUT + 1);
} /**
* Recover an abandoned lock
* @param mixed $key Item to lock
* @return bool Was the lock acquired?
*/
protected static function recover($key){ $redis = self::getRedis(); if(($lockTimeout = $redis->get("Lock:{$key}")) > time())
{
//锁还没有过期
return false;
} $timeout = self::timeout();
$currentTimeout = $redis->getset("Lock:{$key}", $timeout); if($currentTimeout != $lockTimeout)
{
return false;
} self::$expire = $timeout;
return true;
}
} ?>