基于redis的分布式锁

<?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;
    }
}

?>
原文地址:https://www.cnblogs.com/siqi/p/3959517.html