1. 程式人生 > >php鎖機制

php鎖機制

檔案鎖

class fileLock
{
    private $fp = '';
    private $filePath = '';
    public function init($init=array())
    {
        // 檔案路徑
        $this->path = \zc::get('path', 'lock');
        // 生成檔案的粒度,為0時,只生成一個檔案
        // 設定粒度 維持一定量連線
        $this->hashNum = isset($init[0])?$init[0]:0;
        //加鎖超時時間
        $this
->wait = isset($init[1])?$init[1]:0.3; // 開啟檔案的模式 // a+ 讀寫方式 指向尾部 b 表示二進位制 $this->mode = isset($init[2])?$init[2]:'a+b'; } public function name($name) { if (isset($this->fp[$name])) { return; } if ($this->hashNum
== 0) { $this->filePath = $this->path . DIRECTORY_SEPARATOR . $name; } else { $this->filePath = $this->path . DIRECTORY_SEPARATOR . $this->createLockFile($name, $this->hashNum); } $dir = dirname($this->filePath); if (! is_dir
($dir)) { \zc::make('file')->mkdirs($dir, 0777); } $this->fp[$name] = fopen($this->filePath, $this->mode); if (! $this->fp[$name]) { unset($this->fp[$name]); throw new fileLock_Exception('The lock file "' . $name . '" open failed!', '100002'); } } private function createLockFile($name = 'test', $hashNum = 10) { $rand = mt_rand(1, $hashNum); $crc = abs(crc32($name)); if ($crc & 0x80000000) { $crc ^= 0xffffffff; $crc += 1; } return $name . '_' . ($crc % $rand); } public function lock($name, $nonBlockingLock = true) { $this->name($name); if ($nonBlockingLock){ //非阻塞 return flock($this->fp[$name], $lockType | LOCK_NB); } else { $startTime = microtime(true); $canWrite = false; do { $canWrite = flock($this->fp[$name], LOCK_EX); if (! $canWrite) { usleep(rand(10, 1000)); } } while ((! $canWrite) && ((microtime(true) - $startTime) < $this->wait)); return $canWrite; } } public function readLock($name) { $this->name($name); return $this->lock($name, LOCK_SH); } public function unlock($name) { if ($this->fp[$name]) { if (! flock($this->fp[$name], LOCK_UN)) { return $this->unlock($name); } return true; } else { return true; } } public function __destruct() { if (! empty($this->fp)) { foreach ($this->fp as $k => $v) { fclose($v); unset($this->fp[$k]); } } } } class fileLock_Exception extends \Exception { }

sem鎖

if (! function_exists('ftok')) {

    function ftok($filename = "", $proj = "")
    {
        if (empty($filename) || ! file_exists($filename)) {
            return - 1;
        } else {
            $filename = $filename . (string) $proj;
            for ($key = array(); sizeof($key) < strlen($filename); $key[] = ord(substr($filename, sizeof($key), 1)));
            return dechex(array_sum($key));
        }
    }
}

class semLock
{

    private $sem_id = '';

    private $filePath = '';

    public function __construct()
    {
        $this->path = \zc::get('path', 'lock');
        $this->hashNum = 0;
        $this->mode = 'a+b';
        $this->max_acquire = 1;
        $this->perm = '0666';
    }

    public function set($key, $val = '')
    {
        if (is_array($key)) {
            foreach ($key as $k => $v) {
                $this->$k = $v;
            }
        } else {
            $this->$key = $val;
        }
        return $this;
    }

    public function name($name)
    {
        if (isset($this->sem_id[$name])) {
            return;
        }
        if ($this->hashNum == 0) {
            $this->filePath = $this->path . DIRECTORY_SEPARATOR . $name;
        } else {
            $this->filePath = $this->path . DIRECTORY_SEPARATOR . $this->createLockFile($name, $this->hashNum);
        }
        $dir = dirname($this->filePath);
        if (! is_dir($dir)) {
            \zc::obj('file')->mkdirs($dir, 0777);
        }
        $key = ftok($this->filePath, $this->mode);
        if ($key == - 1) {
            throw new semLock_Exception('The lock file "' . $name . '" open failed!', '100002');
        }
        $this->sem_id[$name] = sem_get($key, $this->max_acquire, $this->perm);
        if (! $this->sem_id[$name]) {
            unset($this->sem_id[$name]);
            throw new semLock_Exception('The sem id is empty!', '100003');
        }
    }

    private function createLockFile($name = 'test', $hashNum = 10)
    {
        $rand = mt_rand(1, $hashNum);
        $crc = abs(crc32($name));
        if ($crc & 0x80000000) {
            $crc ^= 0xffffffff;
            $crc += 1;
        }
        return $name . '_' . ($crc % $rand);
    }

    public function lock($name, $nonBlockingLock = false)
    {
        $this->name($name);
        return sem_acquire($this->sem_id[$name], $nonBlockingLock);
    }

    public function unlock($name)
    {
        if ($this->sem_id[$name]) {
            if (! sem_release($this->sem_id[$name])) {
                clearstatcache();
                return $this->unlock($name);
            }
            return true;
        } else {
            return true;
        }
    }

    function __destruct()
    {
        if (! empty($this->sem_id)) {
            foreach ($this->sem_id as $k => $v) {
                sem_remove($v);
                unset($this->sem_id[$k]);
            }
        }
    }
}

class semLock_Exception extends \Exception
{
}