PHP 进程锁定问题

PHP 进程锁定问题

今天看了一个 PHP 进程锁定的文章,

http://www.cnblogs.com/sunli/archive/2009/11/24/1609553.html

刚好,前几天也写了一个 进程锁定的类,这个类要比上面的文章里面提到的更加强大一写。

1. 区分读锁定 和 写 锁定。

    如果每次都使用 写锁定,那么连多个进程读取一个文件也要排队,这样的效率肯定不行。

2. 区分 阻塞 与 非 阻塞模式。

    一般来说,如果一个进程在写一个文件的时候,另外一个进程应该被阻塞,但是,很多时候,我们可以先干点别的事情,

然后再判断一下是否有其他人在写文件,如果没有,再加入数据,这样的效率更高。

 

3. 修复了 锁定文件在linux 上的bug,特别是 在 gfs 文件系统上的bug。

 

代码如下:

 

<? php
class  File_Lock
{
    
private   $name ;

    
private   $handle ;

    
private   $mode ;

    
function  __construct( $filename ,   $mode   =   ' a+b '
    {
        
global   $php_errormsg ;
        
$this -> name    =   $filename ;
        
$path   =   dirname ( $this -> name);
        
if  ( $path   ==   ' . '   ||   ! is_dir ( $path )) {
            
global   $config_file_lock_path ;
            
$this -> name  =   str_replace ( array ( " / " ,   " \\ " ) ,   array ( " _ " ,   " _ " ) ,   $this -> name);
            
if  ( $config_file_lock_path   ==   null ) {
                
$this -> name  =   dirname ( __FILE__ .   " /lock/ "   .   $this -> name;
            } 
else  {
                
$this -> name  =   $config_file_lock_path   .   " / "   .   $this -> name;
            }
        }
        
$this -> mode    =   $mode ;
        
$this -> handle  =  @ fopen ( $this -> name ,   $mode );
        
if  ( $this -> handle  ==   false ) {
            
throw   new   Exception ( $php_errormsg );
        }
    }

    
public   function  close()
    {
        
if  ( $this -> handle  !==   null  ) {
            @
fclose ( $this -> handle);
            
$this -> handle  =   null ;
        }
    }

    
public   function  __destruct() 
    {
        
$this -> close();
    }

    
public   function  lock( $lockType ,   $nonBlockingLock   =   false )
    {
        
if  ( $nonBlockingLock ) {
            
return   flock ( $this -> handle ,   $lockType   |  LOCK_NB);
        } 
else  {
            
return   flock ( $this -> handle ,   $lockType );
        }
    }

    
public   function  readLock()
    {
        
return   $this -> lock(LOCK_SH);
    }

    
public   function  writeLock( $wait   =   0.1 )
    {
        
$startTime   =   microtime ( true );
        
$canWrite   =   false ;
        
do  {
            
$canWrite   =   flock ( $this -> handle ,  LOCK_EX);
            
if ( ! $canWrite ) {
                
usleep ( rand ( 10 ,   1000 )); 
            }
        } 
while  (( ! $canWrite &&  (( microtime ( true -   $startTime <   $wait )); 
    }

    
/* *
     * if you want't to log the number under multi-thread system,
     * please open the lock, use a+ mod. then fopen the file will not
     * destroy the data.
     * 
     * this function increment a delt value , and save to the file.
     * 
     * @param int $delt
     * @return int
     
*/
    
public   function  increment( $delt   =   1 )
    {
        
$n   =   $this -> get();
        
$n   +=   $delt ;
        
$this -> set( $n );
        
return   $n ;
    }

    
public   function  get()
    {
        
fseek ( $this -> handle ,   0 );
        
return  (int) fgets ( $this -> handle);
    }
    
    
public   function  set( $value )
    {
        
ftruncate ( $this -> handle ,   0 );
        
return   fwrite ( $this -> handle ,  ( string ) $value );
    }

    
public   function  unlock()
    {
        
if  ( $this -> handle  !==   null  ) {
            
return   flock ( $this -> handle ,  LOCK_UN);
        } 
else  {
            
return   true ;
        }
    }
}
?>

 

测试代码:

 

<? php
/* *
 * 进行写锁定的测试
 * 打开线程1
 
*/
require ( " file_lock.php " );
$lock   =   new  File_Lock( dirname ( dirname ( __FILE__ ))  .   " /FileLock.lock " );

/* * 单个线程锁定的速度 1s 钟 3万次。 * */
/* * 两个线程写,两万的数据 大概要 7s 钟 */
/* * 一个线程写,一万的数据 大概要 3.9s 钟,居然两个文件同时写,要快一点 */
/* * 不进行锁定,一个进程 写大概要 2.8s 钟,加锁是有代价的。  */
/* * 不进行锁定,两个进程 分布不是很均匀,而且大多数都冲突  */

$lock -> writeLock();
$lock -> increment();
$lock -> unlock();

while  ( $lock -> get()  <   2 ) {
    
usleep ( 1000 );
}
sleep ( 1 );
echo   " begin to runing \n " ;
$t1   =   microtime ( true );
for  ( $i   =   0 $i   <   10000 $i ++ )
{
    
$lock -> writeLock();
    
$lock -> increment( 1 );
    
$lock -> unlock();
}
$t2   =   microtime ( true -   $t1 ;
echo   $t2 ;
?>

 

我增加了一个 increment 的函数,可以实现简单的线程同步,让两个进程同时执行某段代码,当然,这个有一定的误差

这里的误差是 0.001s。

 

把这个类简单的用到 前面的memcache 消息队列中 http://www.cnblogs.com/niniwzw/archive/2009/11/17/1604677.html

就可以实现 线程安全的消息队列。

posted @ 2009-11-24 16:23 暮夏 阅读( ...) 评论( ...) 编辑 收藏
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值