国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > PHP > 正文

PHP flock文件鎖詳解介紹

2024-05-04 21:57:42
字體:
來源:轉載
供稿:網友

為了確保操作的有效性和完整性,可以通過鎖機制將并發狀態轉換成串行狀態.作為鎖機制中的一種,PHP的文件鎖也是為了應對資源競爭.假設一個應用場景,在存在較大并發的情況下,通過fwrite向文件尾部多次有序的寫入數據,不加鎖的情況下會發生什么?多次有序的寫入操作相當于一個事務,我們此時需要保證這個事務的完整性.

bool flock ( int handle, int operation [, int &wouldblock] );

flock() 操作的 handle 必須是一個已經打開的文件指針.operation 可以是以下值之一:

1.要取得共享鎖定(讀取程序),將 operation 設為 LOCK_SH(PHP 4.0.1 以前的版本設置為 1)

2.要取得獨占鎖定(寫入程序),將 operation 設為 LOCK_EX(PHP 4.0.1 以前的版本中設置為 2)

3.要釋放鎖定(無論共享或獨占),將 operation 設為 LOCK_UN(PHP 4.0.1 以前的版本中設置為 3)

4.如果你不希望 flock() 在鎖定時堵塞,則給 operation 加上 LOCK_NB(PHP 4.0.1 以前的版本中設置為 4)

建兩個文件

實例代碼如下:

(1) a.php

  1. ?$file = "temp.txt";      
  2. $fp = fopen($file , 'w');      
  3. if(flock($fp , LOCK_EX)){      
  4.      fwrite($fp , "abcn");      
  5.      sleep(10);      
  6.      fwrite($fp , "123n");      
  7.     flock($fp , LOCK_UN);      
  8. }      
  9. fclose($fp); 

(2) b.php

  1. ?$file = "temp.txt";      
  2. $fp = fopen($file , 'r');      
  3. echo fread($fp , 100);      
  4. fclose($fp); 

運行 a.php 后,馬上運行 b.php ,可以看到輸出:

abc

等 a.php 運行完后運行 b.php ,可以看到輸出:

abc

123

顯然,當 a.php 寫文件時數據太大,導致時間比較長時,這時 b.php 讀取數據不完整

修改 b.php 為:

實例代碼如下:

  1. ?$file = "temp.txt";      
  2. $fp = fopen($file , 'r');      
  3. if(flock($fp , LOCK_EX)){      
  4.     echo fread($fp , 100);      
  5.     flock($fp , LOCK_UN);      
  6. else{      
  7.     echo "Lock file failed...n";      
  8. }      
  9. fclose($fp);  

運行 a.php 后,馬上運行 b.php ,可以發現 b.php 會等到 a.php 運行完成后(即 10 秒后)才顯示:

abc
123

讀取數據完整,但時間過長,他要等待寫鎖釋放.修改 b.php 為:

實例代碼如下:

  1. ?$file = "temp.txt";      
  2. $fp = fopen($file , 'r');      
  3. if(flock($fp , LOCK_SH | LOCK_NB)){      
  4.     echo fread($fp , 100);      
  5.     flock($fp , LOCK_UN);      
  6. else{      
  7.     echo "Lock file failed...n";      
  8. }      
  9. fclose($fp);  

運行 a.php 后,馬上運行 b.php ,可以看到輸出:

Lock file failed…

證明可以返回鎖文件失敗狀態,而不是向上面一樣要等很久.

結論:

建議作文件緩存時,選好相關的鎖,不然可能導致讀取數據不完整,或重復寫入數據.file_get_contents 好像選擇不了鎖,不知道他默認用的什么鎖,反正和不鎖得到的輸出一樣,是不完整的數據.

我是要做文件緩存,所以只需要知道是否有寫鎖存在即可,有的話就查數據庫就可以了.多次同時執行,雖然都寫了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()釋放鎖.

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

但是什么時候使用lock_ex什么時候使用lock_sh呢?

讀的時候:

如果不想出現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寫完并釋放鎖之后才進行讀. 

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 犍为县| 六枝特区| 疏勒县| 新乡市| 平利县| 兴宁市| 黎城县| 凤冈县| 格尔木市| 梨树县| 梧州市| 华宁县| 德清县| 上饶县| 黎平县| 方城县| 微山县| 武定县| 罗平县| 波密县| 宽甸| 汕头市| 安多县| 奉化市| 洮南市| 宣恩县| 双流县| 崇阳县| 郯城县| 桑植县| 旅游| 罗江县| 海盐县| 客服| 宜兴市| 普陀区| 上高县| 临桂县| 岳西县| 宜春市| 辉县市|