有时候在PHP程序中同时只允许一个进程在操作或者只想让一个进程去执行,这时就需要加锁,在网络上找到了phplock这个项目。phplock用于多进程模式下PHP并发操作加锁,以防止并发对同一文件的读写操作错误和缓存失效时,大量请求直接穿透到数据库,造成数据库压力宕机。
<?php
/**
* PHPLock进程锁
* 本进程锁用来解决php在并发时候的锁控制
* 他根据文件锁来模拟多个进程之间的锁定,效率不是非常高。如果文件建立在内存中,可以大大提高效率。
* PHPLOCK在使用过程中,会在指定的目录产生$hashNum个文件用来产生对应粒度的锁。不同锁之间可以并行执行。
* 这有点类似mysql的innodb的行级锁,不同行的更新可以并发的执行。
* @link http://code.google.com/p/phplock/
* @author sunli
* @blog http://sunli.cnblogs.com
* @svnversion $Id$
* @version v1.0 beta1
* @license Apache License Version 2.0
* @copyright [email protected]
*/
class PHPLock
{
//文件锁存放路径
private $path = null;
//文件句柄
private $fp = null;
//锁粒度,设置越大粒度越小
private $hashNum = 100;
//cache key
private $name=null;
//是否存在eaccelerator标志
private $eAccelerator = false;
/**
* 构造函数
* 传入锁的存放路径,及cache key的名称,这样可以进行并发
* @param string $path 锁的存放目录,以"/"结尾
* @param string $name cache key
*/
public function __construct($name,$path='lock\\')
{
//判断是否存在eAccelerator,这里启用了eAccelerator之后可以进行内存锁提高效率
$this->eAccelerator = function_exists("eaccelerator_lock");
if(!$this->eAccelerator)
{
$this->path = $path.($this->_mycrc32($name) % $this->hashNum).'.lock';
}
$this->name = $name;
}
public function __destruct()
{
$this->unlock();
}
/**
* crc32
* crc32封装
* @param int $string
* @return int
*/
private function _mycrc32($string)
{
$crc = abs (crc32($string));
if ($crc & 0x80000000) {
$crc ^= 0xffffffff;
$crc += 1;
}
return $crc;
}
/**
* 加锁
* Enter description here ...
*/
public function lock()
{
//如果无法开启ea内存锁,则开启文件锁
if(!$this->eAccelerator)
{
//配置目录权限可写
$this->fp = fopen($this->path, 'w+');
if($this->fp === false)
{
return false;
}
return flock($this->fp, LOCK_EX);
}else{
return eaccelerator_lock($this->name);
}
}
/**
* 解锁
* Enter description here ...
*/
public function unlock()
{
if(!$this->eAccelerator)
{
if($this->fp !== false)
{
flock($this->fp, LOCK_UN);
clearstatcache();
fclose($this->fp);
}
}else{
return eaccelerator_unlock($this->name);
}
}
}
测试的代码
<?php
require 'class.phplock.php';
$lock = new PHPLock('key_name');
if($lock->lock()){
//do something here
//进程安全的操作
$lock->unlock();
}
else{
//do something here
}
//使用过程中需要注意下文件锁所在路径需要有写权限.
需要注意的是在部分操作系统中,flock() 以处理级执行。当用一个多线程服务器 API(比如 ISAPI)时,可能不可以依靠 flock() 来保护文件,因为在同一服务器内运行在其它线程的 PHP 脚本可以对该文件进行处理。
参考链接:
并发下常见的加锁及锁的PHP具体实现
phplock
best way to obtain a lock in php