• 关键读写关键的锁定问题


      在文件的读写的过程中会用到一个PHP函数flock()。

      为了确保操作的有效性和完整性,可以通过锁机制将并发状态转换成穿行状态。假设一个应用场景:在存在较大并发的情况下,通过fwrite向文件尾部多次有序的写入数据,不加锁的情况下会发生什么?多次有序的写入操作相当于一个事务,我们此时需要保证这个事务的完整性。

      函数flock():

    语法

    flock(file,lock,block)
    参数描述
    file 必需。规定要锁定或释放的已打开的文件。
    lock 必需。规定要使用哪种锁定类型。
    block 可选。若设置为 1 或 true,则当进行锁定时阻挡其他进程。

     

     


    说明

    flock() 操作的 file 必须是一个已经打开的文件指针。

    lock 参数可以是以下值之一:

    • 要取得共享锁定(读取的程序),将 lock 设为 LOCK_SH(PHP 4.0.1 以前的版本设置为 1)。
    • 要取得独占锁定(写入的程序),将 lock 设为 LOCK_EX(PHP 4.0.1 以前的版本中设置为 2)。
    • 要释放锁定(无论共享或独占),将 lock 设为 LOCK_UN(PHP 4.0.1 以前的版本中设置为 3)。
    • 如果不希望 flock() 在锁定时堵塞,则给 lock 加上 LOCK_NB(PHP 4.0.1 以前的版本中设置为 4)。

    示例说明:

      建立两个文件a.php和b.php

    <?php
    //a.php
    
    $file = "temp.txt";
    $fp = fopen($file,"w");
    if(flock($fp,LOCK_EX)){
        fwrite($fp,"abc\r\n");
        sleep(10);
        fwrite($fp,"123\r\n");
        flock($fp,LOCK_UN);
    }
    fclose($fp);
    ?>
    
    <?php
    //b.php
    $file = "temp.txt";
    $fp = fopen($file,"r");
    if(flock($fp,LOCK_SH)){
        echo fread($fp,1024);
        flock($fp,LOCK_UN);
    }else{
        echo "文件被独占锁锁住了。。。";
    }
    fclose($fp);
    ?>

      先运行a.php,然后马上运行b.php,会发现b.php要等a.php运行完成后(即写入大量数据完成后),b.php才显示a.php写入的数据。

      现在将b.php修改为:

    <?php
    $file = "temp.txt";
    $fp = fopen($file,"r");
    if(flock($fp,LOCK_SH|LOCK_NB)){
        echo fread($fp,1024);
        flock($fp,LOCK_UN);
    }else{
        echo "文件被独占锁锁住了。。。";
    }
    fclose($fp);
    ?>

      此时进行同样的操作,会发现b.php不等a.php写完数据(运行完)就立即显示"文件被独占锁锁住了。。。"

      结论:作文件缓存时,选好相关锁,不然可能导致读取数据不完整,或重复写入数据。(file_get_contents的锁不清楚,如上操作会得到不完整的数据。)

      多次同时执行,虽然都写了100行,但是事务1和事务2的数据交错写入,这并不是我们想要的结果。我们要的是事务完整的执行。此时需要锁机制flock就保证了在第一个事务执行完后再执行第二个。当某一个事务执行完flock时,因为我们在这里添加的是LOCK_EX(独占锁定),所以所有对资源的操作都会被阻塞,只有当该事务执行完后,后面的事务才会执行。

      什么时候用LOCK_EX,什么时候用LOCK_SH呢?

      读的时候:如果不想出现dirty数据,那么最好使用LOCK_SH共享锁。可以考虑以下三种情况:

      1.如果读的时候没有加共享锁,那么其它程序要写的话都会立即些成功。如果正好读了一半,然后被其它程序给写了,那么读的后一半就有可能跟前一半对不上(前一半是修改前的,后一半是修改后的);

      2.如果读的时候加上了共享锁(因为只是读,没必要使用排他锁即独占锁),这个时候,其它程序开始写,这个写程序没有使用锁,那么写程序会直接修改这个文件,也会导致前面一样的问题;

      3.最理想的情况是,读的时候加共享锁LOCK_SH,写的时候也进行加独占锁LOCK_EX,这样写程序会等着读程序完成之后才进行操作,而不会出现贸然操作的情况。

      写的时候:如果多个写程序不加锁,同时对文件进行操作,那么最后的数据有可能一部分是a程序写的,一部分是b程序写的。所以最理想的情况还是如上第三点:读的时候加共享锁LOCK_SH,写的时候也进行加独占锁LOCK_EX。

  • 相关阅读:
    PhoneGap打包webApp
    mysql触发器实例说明
    mysql索引总结
    python:生成器
    python:装饰器
    python:局部变量与全局变量
    python:函数
    python:文件操作
    python:集合及其运算
    python:字符串常用函数
  • 原文地址:https://www.cnblogs.com/thinksasa/p/2938404.html
Copyright © 2020-2023  润新知