有时候在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