萬盛學電腦網

 萬盛學電腦網 >> 網絡編程 >> php編程 >> PHP文件鎖用法詳解

PHP文件鎖用法詳解

PHP出現文件鎖與mysql表鎖有大概想的用法,就是同一時間只能讓一個人操作,這樣就避免了同時有多個人操作同一文件,這樣導致數據丟失的情況了,下面我來給大家介紹PHP文件鎖用法。

PHP自帶了文件鎖函數:
bool flock ( int $handle , int $operation [, int &$wouldblock ] )
$handle 是打開的文件指針;
$operation 可以是
“LOCK_SH”,共享鎖定;“LOCK_EX”,獨占鎖定;“LOCK_UN”,釋放鎖定;“LOCK_NB”,防止flock鎖定時堵塞。
這裡主要說說“LOCK_EX”和“LOCK_NB”。

比如我們有兩個文件,如下。


flocka.php

 代碼如下 復制代碼

$file = 'temp.txt';
    $fp = fopen($file,'a');
 
    for($i = 0;$i < 5;$i++)
    {
        fwrite($fp, "11111111n");
        sleep(1);
    }
 
    fclose($fp);

flockb.php

 代碼如下 復制代碼 $file = 'temp.txt';
    $fp = fopen($file,'a');
 
    for($i = 0;$i < 5;$i++)
    {
        fwrite($fp, "22222222n");
    }
 
    fclose($fp);

先運行flocka.php,然後馬上運行flockb.php。
結果:
11111111
22222222
22222222
22222222
22222222
22222222
11111111
11111111
11111111
11111111
說明不加文件鎖時,兩個文件會同時對txt文件進行寫入操作。
下面修改一下兩個php文件的代碼。
flocka.php

 代碼如下 復制代碼 $file = 'temp.txt';
    $fp = fopen($file,'a');
 
    if(flock($fp,LOCK_EX))
    {
        for($i = 0;$i < 5;$i++)
        {
            fwrite($fp, "11111111n");
            sleep(1);
        }
        flock($fp,LOCK_UN);
    }
    fclose($fp);

flockb.php

 代碼如下 復制代碼 $file = 'temp.txt';
    $fp = fopen($file,'a');
 
    if(flock($fp,LOCK_EX))
    {
        for($i = 0;$i < 5;$i++)
        {
            fwrite($fp, "22222222n");
        }
         flock($fp,LOCK_UN);
    }
 
    fclose($fp);

同樣先運行flocka.php,然後馬上運行flockb.php。
會發現在flocka.php運行結束前,flockb.php一直處於等待狀態,只有當flocka.php運行結束後,flockb.php才會繼續執行。
輸出結果:
11111111
11111111
11111111
11111111
11111111
22222222
22222222
22222222
22222222
22222222
另外,在執行flock時,文件鎖會自動釋放。


還有一種辦法


如下代碼簡單模擬了這種事務並發狀態: process1.php

 代碼如下 復制代碼  <?php
    $num = 100;
    $filename = "processdata.txt";
 
    $fp = fopen($filename, "a");
    for ($i = 0; $i < $num; $i++) {
        fwrite($fp, "process1: " . $i . "rn");
        usleep(100000);
    }
    fclose($fp);
    ?>

我們需要先執行第一個事務,在processdata.txt文件中寫入這100行。

process2.php

 代碼如下 復制代碼

 <?php
    $num = 100;
    $filename = "processdata.txt";
 
    $fp = fopen($filename, "a");
    for ($i = 0; $i < $num; $i++) {
        fwrite($fp, "process2: " . $i . "rn");
        usleep(100000);
    }
    fclose($fp);
    ?>

第二個事務,繼續向processdata.txt文件中寫入100行。

第二個事務,繼續向processdata.txt文件中寫入100行。

多次同時執行,雖然都寫了100行,但是事務1和事務2的數據交錯寫入,這並不是我們想要的結果。我們要的是事務完整的執行,此時我們需要有個機制去保證在第一個事務執行完後再執行第二個。在PHP中,flock函數完成了這一使命。在事物1和事務2的循環前面都加上: flock($fp, LOCK_EX); 就能滿足我們的需求,將兩個事務串行。

當某一個事務執行完flock時,因為我們在這裡添加的是LOCK_EX(獨占鎖定),所以所有對資源的操作都會被阻塞,只有當事務執行完成後,後面的事務才會執行。我們可以通過輸出當前的時間的方法來確認這一點。

關於在尾部追加寫入,在unix系統的早期版本中存在一個並發寫入的問題,如果要在尾部追加,需要先lseek位置,再write。當多個進程同時操作時,會因為並發導致的覆蓋寫入的問題,即兩個進程同時獲取尾部的偏移後,先後執行write操作,後面的操作會將前面的操作覆蓋。這個問題在後面以添加打開時的O_APPEND操作而得到解決,它將查找和寫入操作變成了一個原子操作。

在PHP的fopen函數的實現中,如果我們使用a參數在文件的尾部追加內容,其調用open函數中oflag參數為 O_CREAT|O_APPEND,即我們使用追加操作不用擔心並發追加寫入的問題。

在PHP的session默認存儲實現中也用到了flock文件鎖,當session開始時就調用PS_READ_FUNC,且以O_CREAT | O_RDWR | O_BINARY 打開session數據文件,此時會調用flock加上寫鎖,如果此時有其它進程訪問此文件(即同一用戶再次發起對當前文件的請求),就會顯示頁面加載中,進程被阻塞了。加寫鎖其出發點是為了保證此次會話中對session的操作事務能完整的執行,防止其它進程的干擾,保證數據的一致性。如果一個頁面沒有session修改操作,可以盡早的調用session_write_close()釋放鎖。

文件鎖是針對文件的鎖,除了這種釋義,還可以理解為用文件作為鎖。在實際工作中,有時為確保單個進程的執行,我們會在程序執行前判斷文件是否存在,如果不存在則創建一個空文件,在進程結束後刪除這個空文件,如果存在,則不執行。

copyright © 萬盛學電腦網 all rights reserved