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

PHP 模擬 flock 實現跨平台檔案鎖定機制

     編輯:PHP 綜合知識

flock() 在某些系統(特別是 Windows 舊版 PHP)上不可靠或不支援。本文提供一種以標記檔案模擬獨佔鎖的思路,不依賴系統底層鎖 API。

核心原理

  • 建立兩個標記檔:.{$lock}0(申請鎖)、.{$lock}1(持有鎖)
  • 雙重檢查機制:先建立 0 標記,確認 1 標記不存在才建立 1 標記並取得鎖
  • 釋放鎖時刪除兩個標記檔
  • 加入重試次數與 usleep 避免忙等待佔用 CPU

完整實作代碼

<?php
/**
 * 申請檔案鎖(模擬 flock)
 * @param string $lock  基礎檔名(如 "data.txt")
 * @param int    $tries 最大重試次數
 * @return int  1=成功 0=超時失敗
 */
function lock($lock, $tries) {
    $lock0 = ".{$lock}0";  // 申請標記
    $lock1 = ".{$lock}1";  // 持有標記

    for ($i = 0; $i < $tries; $i++) {
        if (!is_file($lock0)) {
            touch($lock0);               // 建立申請標記
            if (!is_file($lock1)) {
                touch($lock1);           // 建立持有標記
                return 1;                // 成功取得鎖
            }
        }
        usleep(100);  // 讓出 CPU,避免忙等待
    }
    return 0;  // 超時失敗
}

/**
 * 釋放檔案鎖
 */
function unlock($lock) {
    unlink(".{$lock}1");
    unlink(".{$lock}0");
}

/* ===== 使用範例 ===== */
$filename = "somefile";
$data = "stuff and things\n";
$tries = 10;

if (lock($filename, $tries)) {
    $h = fopen($filename, "a") or die();
    fwrite($h, $data);
    fclose($h);

    /* 模擬另一程序嘗試寫入(會被鎖住) */
    if (lock($filename, $tries)) {
        $h2 = fopen($filename, "a") or die();
        fwrite($h2, 'check lock');
        fclose($h2);
    } else {
        // echo "第二程序無法取得鎖";
    }

    unlock($filename);
} else {
    // die("首次鎖定失敗");
}
?>

優缺點分析

優點缺點
純 PHP 實作,跨平台相容依賴檔案系統,NFS/網路磁碟可能有延遲導致競態
無需系統級 flock 支援進程異常終止可能殘留標記檔(需定期清理)
邏輯簡單易維護效能不如核心級 flock,高併發場景建議用 Redis/Memcached 分散式鎖

改進建議

  1. 加入 register_shutdown_function('unlock', $lock) 防止腳本異常結束殘留鎖
  2. 標記檔存放於專用暫存目錄,避免業務目錄混雜
  3. 高併發生產環境建議改用 flock()(現代 PHP 已完善支援)或分散式鎖
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved