background image

php 中并发读写文件冲突的解决方案

对于日

IP 不高或者说并发数不是很大的应用,一般不用考虑这些!用一般的文件操作

方法完全没有问题。但如果并发高,在我们对文件进行读写操作时,很有可能多个进程对进
一文件进行操作,如果这时不对文件的访问进行相应的独占,就容易造成数据丢失。
    例如:一个在线聊天室(这里假定把聊天内容写入文件),在同一时刻,用户 A 和用户
B 都要操作数据保存文件,首先是 A 打开了文件,然后更新里面的数据,但这里 B 也正好
也打开了同一个文件,也准备更新里面的数据。当

A 把写好的文件保存时,这里其实 B 已

经打开了文件。但当

B 再把文件保存回去时,这里已经造成了数据的丢失,因为这里 B 用

户完全不知道它所打开的文件在它对其进行更改时,

A 用户也更改了这个文件,所以最后

B 用户保存更改时,用户 A 的更新就被会丢失。
   对于这样的问题,一般的解决方案时当一进程对文件进行操作时,首先对其它进行加锁,
意味着这里只有该进程有权对文件进行读取,其它进程如果现在读,是完全没有问题,但
如果这时有进程试图想对其进行更新,会遭到操作拒绝,先前对文件进行加锁的进程这时
如果对文件的更新操作完毕,这就释放独占的标识,这时文件又恢复到了可更改的状态。接
下来同理,如果那个进程在操作文件时,文件没有加锁,这时,它就可以放心大胆的对文
件进行锁定,独自享用。
   一般的方案会是:

代码如下

:

$fp=fopen('/tmp/lock.txt','w+');

if (flock($fp,LOCK_EX)){
    fwrite($fp,"Write something here\n");
    flock($fp,LOCK_UN);
}else{
    echo 'Couldn\'t lock the file !';
}
fclose($fp);

但在

PHP 中,flock 似乎工作的不是那么好!在多并发情况下,似乎是经常独占资源,

不即时释放,或者是根本不释放,造成死锁,从而使服务器的

cpu 占用很高,甚至有时候

会让服务器彻底死掉。好像在很多

linux/unix 系统中,都会有这样的情况发生。所以使用

flock 之前,一定要慎重考虑。
那么就没有解决方案了吗?其实也不是这样的。如果

flock()我们使用得当,完全可能解决死

锁的问题。当然如果不考虑使用

flock()函数,也同样会有很好的解决方案来解决我们的问题。

经过我个人的搜集和总结,大致归纳了解决方案有如下几种。
方案一:对文件进行加锁时,设置一个超时时间。大致实现如下:

代码如下

:

if($fp=fopen($fileName,'a')){

 $startTime=microtime();
 do{
  $canWrite=flock($fp,LOCK_EX);
  if(!$canWrite){
   usleep(round(rand(0,100)*1000));
  }
 }while((!$canWrite)&&((microtime()-$startTime)<1000));