首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP flock() 文件鎖機制詳解與併發讀寫實戰範例

     編輯:PHP 相關知識

flock() 是 PHP 實現輕量級諮詢式文件鎖的核心函數,適用於多進程環境下對同一文件的協同訪問控制。本文詳細解析參數、行為差異,並提供三個實戰場景代碼。

函數原型與參數

bool flock(resource $handle, int $operation [, int &$wouldblock ])
  • $handle:fopen() 返回的文件資源指標。
  • $operation:
    • LOCK_SH:共享鎖(讀鎖),多進程可同時持有。
    • LOCK_EX:獨占鎖(寫鎖),同一時間僅一進程持有。
    • LOCK_UN:釋放鎖(共享/獨占通用)。
    • LOCK_NB:非阻塞模式(Windows 不支援),鎖定失敗立即返回而非等待。
  • $wouldblock:若傳入且鎖會阻塞,則設為 true(Windows 不支援)。

返回:成功 true,失敗 false。

關鍵行為變更(PHP 5.3.2+)

舊版本腳本結束或 fclose() 會自動釋放鎖;5.3.2 起必須顯式呼叫 flock($fp, LOCK_UN) 釋放,否則鎖可能殘留導致併發異常。

限制與注意事項

  • 諮詢式鎖:僅限協作進程間生效,無法阻止繞過 flock 直接操作文件的程式。
  • 多線程 SAPI(如 ISAPI)下,同一伺服器實例內的其他線程可能繞過鎖直接訪問文件。
  • NFS/網絡文件系統上 flock 可靠性取決於底層實現,生產環境建議驗證或改用資料庫鎖/Redis 分佈式鎖。

實戰範例

場景一:安全讀取——避免讀到寫入一半的內容

<?php
// writer.php 寫入端
$fp = fopen('data.txt', 'c+');
flock($fp, LOCK_EX);
ftruncate($fp, 0);
fwrite($fp, '新內容 ' . time());
flock($fp, LOCK_UN);
fclose($fp);

// reader.php 讀取端
function safeRead($path) {
    $fp = fopen($path, 'r');
    if (flock($fp, LOCK_SH)) {          // 獲取共享鎖
        $content = stream_get_contents($fp);
        flock($fp, LOCK_UN);
        fclose($fp);
        return $content;
    }
    fclose($fp);
    return false;                       // 非阻塞模式下獲取失敗
}

場景二:共享鎖下禁止寫入驗證

<?php
$fp = fopen('test.txt', 'a');
flock($fp, LOCK_SH);                    // 持有讀鎖
$written = fwrite($fp, 'data');         // 嘗試寫入
var_dump($written);                     // int(0) 寫入失敗,文件未變
fclose($fp);

持有 LOCK_SH 時嘗試寫入會失敗(返回 0),必須先釋放或升級為 LOCK_EX。

場景三:簡易併發隊列——追加寫入與讀取

<?php
// 寫入:追加模式 + 獨占鎖
function T_put($file, $str) {
    $fp = fopen($file, 'a');
    if (flock($fp, LOCK_EX)) {
        fwrite($fp, $str . PHP_EOL);
        flock($fp, LOCK_UN);
    }
    fclose($fp);
}

// 讀取:讀模式 + 共享鎖
function T_get($file, $len = 8192) {
    $fp = fopen($file, 'r');
    $data = '';
    if (flock($fp, LOCK_SH)) {
        $data = fread($fp, $len);
        flock($fp, LOCK_UN);
    }
    fclose($fp);
    return $data;
}

此模式模擬「單寫多讀」併發,適合日誌記錄、簡易任務隊列等低頻場景。高併發或分佈式環境請改用 Redis/RabbitMQ 等專業中間件。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved