疯狂TEST

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::

[转]PHP并发操作下的加锁

有这么一个需求:生成文件的时候,由于多用户都有权限进行生成,防止并发下,导致生成的结果出现错误,需要对生成的过程进行加锁,只容许一个用户在 一个时间内进行操作,这个时候就需要用到锁了,将这个操作过程锁起来。在用了cache的时候,cache失效可能导致瞬间的多数并发请求穿透到数据库此 时也可以得需要用锁在同一并发的过程中将这个操作锁定。

针对以上的2种情况,现在的解决方法是对处理过程进行锁机制,通过PHP实现如下:

用到了Eaccelerator的内存锁和文件锁,原理:判断系统中是否安了EAccelerator如果有则使用内存锁,如果不存在,则进行文件锁。根据带入的key的不同可以实现多个锁直接的并行处理,类似Innodb的行级锁。

具体类如下:

01 <?php
02 /**
03  * CacheLock 进程锁,主要用来进行cache失效时的单进程cache获取,防止过多的SQL请求穿透到数据库
04  * 用于解决PHP在并发时候的锁控制,通过文件/eaccelerator进行进程间锁定
05  * 如果没有使用eaccelerator则进行进行文件锁处理,会做对应目录下产生对应粒度的锁
06  * 使用了eaccelerator则在内存中处理,性能相对较高
07  * 不同的锁之间并行执行,类似mysql innodb的行级锁
08  * 本类在sunli的phplock的基础上做了少许修改  http://code.google.com/p/phplock
09  * @author yangxinqi
10  *
11  */
12 class CacheLock
13 {
14     //文件锁存放路径
15     private $path = null;
16     //文件句柄
17     private $fp = null;
18     //锁粒度,设置越大粒度越小
19     private $hashNum = 100;
20     //cache key
21     private $name;
22     //是否存在eaccelerator标志
23     private  $eAccelerator = false;
24      
25     /**
26      * 构造函数
27      * 传入锁的存放路径,及cache key的名称,这样可以进行并发
28      * @param string $path 锁的存放目录,以"/"结尾
29      * @param string $name cache key
30      */
31     public function __construct($name,$path='lock\\')
32     {
33         //判断是否存在eAccelerator,这里启用了eAccelerator之后可以进行内存锁提高效率
34         $this->eAccelerator = function_exists("eaccelerator_lock");
35         if(!$this->eAccelerator)
36         {
37             $this->path = $path.($this->_mycrc32($name) % $this->hashNum).'.txt';
38         }
39         $this->name = $name;
40     }
41      
42     /**
43      * crc32
44      * crc32封装
45      * @param int $string
46      * @return int
47      */
48     private function _mycrc32($string)
49     {
50         $crc = abs (crc32($string));
51         if ($crc & 0x80000000) {
52             $crc ^= 0xffffffff;
53             $crc += 1;
54         }
55         return $crc;
56     }
57     /**
58      * 加锁
59      * Enter description here ...
60      */
61     public function lock()
62     {
63         //如果无法开启ea内存锁,则开启文件锁
64         if(!$this->eAccelerator)
65         {
66             //配置目录权限可写
67             $this->fp = fopen($this->path, 'w+');
68             if($this->fp === false)
69             {
70                 return false;
71             }
72             return flock($this->fp, LOCK_EX);
73         }else{
74             return eaccelerator_lock($this->name);
75         }
76     }
77      
78     /**
79      * 解锁
80      * Enter description here ...
81      */
82     public function unlock()
83     {
84         if(!$this->eAccelerator)
85         {
86             if($this->fp !== false)
87             {
88                 flock($this->fp, LOCK_UN);
89                 clearstatcache();
90             }
91             //进行关闭
92             fclose($this->fp);
93         }else{
94             return eaccelerator_unlock($this->name);
95         }
96     }
97 }
98 ?>

使用如下:

1 $lock = new CacheLock('key_name');
2 $lock->lock();
3 //logic here
4 $lock->unlock();
5 //使用过程中需要注意下文件锁所在路径需要有写权限.
posted on 2011-04-11 15:44  crazyzzj  阅读(614)  评论(0)    收藏  举报