学习笔记之PHP文件锁(flock)

来源:互联网 发布:数据网络开关 编辑:程序博客网 时间:2024/05/22 17:29
文件锁函数:
bool flock ( int $handle , int $operation [, int &$wouldblock ] )  
参数说明:
$handle 是已经打开的文件句柄;
$operation 可以是"LOCK_SH"(共享锁定)、"LOCK_EX"(排它锁定)、"LOCK_UN"(释放锁定)、"LOCK_NB"(防止flock锁定时堵塞)
代码示例分析:
       1.两个进程同时向一个文件下数据
        flocka.php
$file = 'test.txt';$fp = fopen($file,'a');if($fp){    for($i = 0;$i < 5;$i++)    {        fwrite($fp, "aaaaaaaa\n");        sleep(1);    }}fclose($fp);flockb.php$file = 'test.txt';$fp = fopen($file,'a');if($fp){    for($i = 0;$i < 5;$i++)    {        fwrite($fp, "bbbbbbbb\n");    }}fclose($fp);
在浏览器上运行flocka.php后马上运行flockb.php文件,在test.txt文件中我们看到结果是:
aaaaaaaa
aaaaaaaa
aaaaaaaa
bbbbbbbb
bbbbbbbb
bbbbbbbb
bbbbbbbb
bbbbbbbb
aaaaaaaa
aaaaaaaa
奇怪了,flocka.php文件还未写完,flockb.php文件就执行了,造成数据混乱!
这种情况我们该如何处理呢? 解决方案就是对每个写进程加排他锁LOCK_EX,我们对两个php文件进行修改如下:
flocka.php
$file = 'test.txt';$fp = fopen($file,'a');if(flock($fp,LOCK_EX)){    for($i = 0;$i < 5;$i++)    {        fwrite($fp, "aaaaaaaa\n");        sleep(1);    }    flock($fp,LOCK_UN);}fclose($fp);flockb.php$file = 'test.txt';$fp = fopen($file,'a');if(flock($fp,LOCK_EX)){    for($i = 0;$i < 5;$i++)    {        fwrite($fp, "bbbbbbbb\n");    }    flock($fp,LOCK_UN);}fclose($fp);
同样的操作步骤后,我们可以看到flockb.php文件并未先于flocka.php文件执行完,而现在test.txt的数据为:
aaaaaaaa
aaaaaaaa
aaaaaaaa
aaaaaaaa
aaaaaaaa
bbbbbbbb
bbbbbbbb
bbbbbbbb
bbbbbbbb
bbbbbbbb
2.一个进程写数据,另一个进程读数据
flockc.php
$fp = fopen("test.txt","a");if($fp){    fwrite($fp,"aaaaaa");    sleep(10);    fwrite($fp,"bbbbbb");}else{    echo "文件打开失败";}fclose($fp);flockd.php$fp = fopen("test.txt","r");if($fp){    echo(fread($fp,1000));    fclose($fp);}else{    echo "文件打开失败!";}
测试步骤: 在浏览器上运行flockc.php,然后马上运行flockd.php
你将会看到flockc.php处于执行中,而flockd.php页面输出 aaaaaa
当flockc.php执行完后,再执行flockd.php,该页面会输出aaaaaabbbbbb
由此我们得知在flockc.php正在写数据时,flockd.php获取到的是脏数据!
我们应该怎样避免这种情况呢?
结合上一个demo的知识,对写加上排它锁,flockc.php代码如下:
$fp = fopen("test.txt","a");if($fp){    flock($fp,LOCK_EX);    fwrite($fp,"aaaaaa");    sleep(10);    fwrite($fp,"bbbbbb");    flock($fp,LOCK_UN);}else{    echo "文件打开失败";}fclose($fp);
继续相同的测试步骤,你会发现,在flockc.php正在执行时,运行flockd.php不会输出任何内容。
这不是我想要的结果,再对flockd.php进行修改,代码如下:
flockd.php
$fp = fopen("test.txt","r");if(flock($fp,LOCK_SH)){    echo(fread($fp,1000));    flock($fp,LOCK_UN);    fclose($fp);}else{    echo "文件打开失败!";}
测试结果是:flockd.php会等到flcokc.php执行完后输出aaaaaabbbbbb

有一位师兄的总结得很好:

读的时候:
如果不想出现dirty数据,那么最好使用lock_sh共享锁。可以考虑以下三种情况:
1. 如果读的时候没有加共享锁,那么其他程序要写的话(不管这个写是加锁还是不加锁)都会立即写成功。如果正好读了一半,然后被其他程序给写了,那么读的后一半就有可能跟前一半对不上(前一半是修改前的,后一半是修改后的)
2. 如果读的时候加上了共享锁(因为只是读,没有必要使用排他锁),这个时候,其他程序开始写,这个写程序没有使用锁,那么写程序会直接修改这个文件,也会导致前面一样的问题
3. 最理想的情况是,读的时候加锁(lock_sh),写的时候也进行加锁(lock_ex),这样写程序会等着读程序完成之后才进行操作,而不会出现贸然操作的情况
写的时候:
如果多个写程序不加锁同时对文件进行操作,那么最后的数据有可能一部分是a程序写的,一部分是b程序写的
如果写的时候加锁了,这个时候有其他的程序来读,那么他会读到什么东西呢?
1. 如果读程序没有申请共享锁,那么他会读到dirty的数据。比如写程序要写a,b,c三部分,写完a,这时候读读到的是a,继续写b,这时候读读到的是ab,然后写c,这时候读到的是abc.
2. 如果读程序在之前申请了共享锁,那么读程序会等写程序将abc写完并释放锁之后才进行读。 

本文学习地址:http://www.cnblogs.com/chenwenbiao/archive/2011/08/01/2123905.html
0 0
原创粉丝点击