文件加鎖,作用是用來做什么?以及使用細節


 

 https://www.cnblogs.com/chenwenbiao/archive/2011/08/01/2123905.html

demo.php

 <?php
 $fp = fopen("file_lock.txt", "w");
 //加鎖
 if (flock($fp, LOCK_EX)) {
   fwrite($fp, "abc\n");
   sleep(10);
   fwrite($fp, "ddd\n");
   echo 1;
   //執行完成解鎖
   flock($fp, LOCK_UN);
 }
 // 關閉文件
 fclose($fp);
                                                                                 
                                                                                 

  lock.go

package main

import (
  "syscall"
  "os"
  "log"
  "time"
)

func main() {
  f, err := os.OpenFile("file_lock.txt", os.O_RDWR, 0777) 
  if err != nil {
    log.Println("open file err:", err)
  }
  for {
    err = syscall.Flock(int(f.Fd()), syscall.LOCK_SH|syscall.LOCK_NB)
    if err != nil {
      log.Println("flock err:", err)
      log.Println("flock err:", syscall.EWOULDBLOCK )
    } else {
      log.Println("lock success")
      return
    }
    time.Sleep(time.Second)
  }

}
                                       
                                       

  開窗口一執行: php demo.php

 

  開窗口二執行: go  lock.go

 

 

 

 

-------------------------------

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

$file  = "temp.txt" ;   
$fp  = fopen ( $file  , 'w' );   
if ( flock ( $fp  , LOCK_EX)){   
      fwrite( $fp  , "abc\n" );   
      sleep(10);   
      fwrite( $fp  , "123\n" );   
     flock ( $fp  , LOCK_UN);   
}   
fclose( $fp );  

(2) b.php

$file  = "temp.txt" ;   
$fp  = fopen ( $file  , 'r' );   
echo  fread ( $fp  , 100);   
fclose( $fp );  

運行 a.php 后,馬上運行 b.php ,可以看到輸出:
abc
等 a.php 運行完后運行 b.php ,可以看到輸出:
abc
123
顯然,當 a.php 寫文件時數據太大,導致時間比較長時,這時 b.php 讀取數據不完整

修改 b.php 為:

$file  = "temp.txt" ;   
$fp  = fopen ( $file  , 'r' );   
if ( flock ( $fp  , LOCK_EX)){   
     echo  fread ( $fp  , 100);   
     flock ( $fp  , LOCK_UN);   
} else {   
     echo  "Lock file failed...\n" ;   
}   
fclose( $fp );  

運行 a.php 后,馬上運行 b.php ,可以發現 b.php 會等到 a.php 運行完成后(即 10 秒后)才顯示:
abc
123
讀取數據完整,但時間過長,他要等待寫鎖釋放。

修改 b.php 為:

$file  = "temp.txt" ;   
$fp  = fopen ( $file  , 'r' );   
if ( flock ( $fp  , LOCK_SH | LOCK_NB)){   
     echo  fread ( $fp  , 100);   
     flock ( $fp  , LOCK_UN);   
} else {   
     echo  "Lock file failed...\n" ;   
}   
fclose( $fp );  

運行 a.php 后,馬上運行 b.php ,可以看到輸出:
Lock file failed…
證明可以返回鎖文件失敗狀態,而不是向上面一樣要等很久。

結論:
建議作文件緩存時,選好相關的鎖,不然可能導致讀取數據不完整,或重復寫入數據。
file_get_contents 好像選擇不了鎖,不知道他默認用的什么鎖,反正和不鎖得到的輸出一樣,是不完整的數據。
我是要做文件緩存,所以只需要知道是否有寫鎖存在即可,有的話就查數據庫就可以了。
測試環境:Linux(Ubuntu 6) , PHP 5.1.2 , Apache 2

再轉:

文件鎖有兩種:共享鎖和排他鎖,也就是讀鎖(LOCK_SH)和寫鎖(LOCK_EX) 
文件的鎖一般這么使用:
  1. $fp = fopen("filename", "a");   
  2. flock($fp, LOCK_SH) or die("lock error")   
  3. $str = fread($fp, 1024);   
  4. flock($fp, LOCK_UN);   
  5. fclose($fp);  

注意fwrite之后,文件立即就被更新了,而不是等fwrite然后fclose之后文件才會更新,這個可以通過在fwrite之后fclose之前讀取這個文件進行檢查 

但是什么時候使用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寫完並釋放鎖之后才進行讀。 

還有一篇也寫得不錯的博文:

http://hxsdit.com/1110

-------------------------------

 

File locking in Linux

29 Jul 2016

Table of contents


Introduction

File locking is a mutual-exclusion mechanism for files. Linux supports two major kinds of file locks:

  • advisory locks
  • mandatory locks

Below we discuss all lock types available in POSIX and Linux and provide usage examples.


Advisory locking

Traditionally, locks are advisory in Unix. They work only when a process explicitly acquires and releases locks, and are ignored if a process is not aware of locks.

There are several types of advisory locks available in Linux:

  • BSD locks (flock)
  • POSIX record locks (fcntl, lockf)
  • Open file description locks (fcntl)

All locks except the lockf function are reader-writer locks, i.e. support exclusive and shared modes.

Note that flockfile and friends have nothing to do with the file locks. They manage internal mutex of the FILE object from stdio.

Reference:

Common features

The following features are common for locks of all types:

  • All locks support blocking and non-blocking operations.
  • Locks are allowed only on files, but not directories.
  • Locks are automatically removed when the process exits or terminates. It’s guaranteed that if a lock is acquired, the process acquiring the lock is still alive.

Differing features

This table summarizes the difference between the lock types. A more detailed description and usage examples are provided below.

  BSD locks lockf function POSIX record locks Open file description locks
Portability widely available POSIX (XSI) POSIX (base standard) Linux 3.15+
Associated with File object [i-node, pid] pair [i-node, pid] pair File object
Applying to byte range no yes yes yes
Support exclusive and shared modes yes no yes yes
Atomic mode switch no - yes yes
Works on NFS (Linux) Linux 2.6.12+ yes yes yes

File descriptors and i-nodes

file descriptor is an index in the per-process file descriptor table (in the left of the picture). Each file descriptor table entry contains a reference to a file object, stored in the file table (in the middle of the picture). Each file object contains a reference to an i-node, stored in the i-node table (in the right of the picture).

A file descriptor is just a number that is used to refer a file object from the user space. A file object represents an opened file. It contains things likes current read/write offset, non-blocking flag and another non-persistent state. An i-node represents a filesystem object. It contains things like file meta-information (e.g. owner and permissions) and references to data blocks.

File descriptors created by several open() calls for the same file path point to different file objects, but these file objects point to the same i-node. Duplicated file descriptors created by dup2() or fork() point to the same file object.

A BSD lock and an Open file description lock is associated with a file object, while a POSIX record lock is associated with an [i-node, pid] pair. We’ll discuss it below.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM