首頁  >  文章  >  後端開發  >  flock php 鎖不成功怎麼辦?

flock php 鎖不成功怎麼辦?

藏色散人
藏色散人原創
2021-11-08 09:32:402234瀏覽

flock php鎖定不成功是因為在isRunning()方法退出後,$file_lock沒有繼續使用導致的,其解決方法就是確保在整個PHP生命期內,檔案句柄都不會被釋放即可。

flock php 鎖不成功怎麼辦?

本文操作環境:Windows7系統、PHP7.1版、DELL G3電腦

flock php 鎖定不成功怎麼辦?

php flock失效問題解決:

這兩天為自己的業餘專案寫了一個方法,用來避免crontab調度的PHP腳本並發執行。

做法

一般透過使用檔案鎖定flock方法,令相同的PHP腳本採用非阻塞鎖定同一個磁碟文件,如果檔案被佔用則會報錯,從而可以腳本立即退出。

現象

但實踐中發現,在controller檔案中直接flock是可以實現的,當把flock的邏輯封裝到其他檔案的一個函數中後就失效了。

原因

調試了半天,突然想起來以前就遇過這個神坑。 。

錯誤代碼如下:

class Crontab
{
    /**
     * 确保任务没有并发执行
     */
    public static function isRunning() {
        global $argv;
        $ident = [];
        foreach ($argv as $idx => $value) {
            $ident[] = $idx . '=' . urlencode($value);
        }
        $ident = md5(implode('&', $ident));
        $lockDir = \Yii::getAlias('@app/runtime/crontab/');
        @mkdir($lockDir, 0755, true);
        $file_lock = fopen($lockDir . $ident, 'w+');
        $wouldBlock = 0;
        flock($file_lock, LOCK_EX | LOCK_NB, $wouldBlock);
        return $wouldBlock;
    }
}
class Crontab
{
    /**
     * 确保任务没有并发执行
     */
    public static function isRunning() {
        global $argv;
 
        $ident = [];
        foreach ($argv as $idx => $value) {
            $ident[] = $idx . '=' . urlencode($value);
        }
        $ident = md5(implode('&', $ident));
 
        $lockDir = \Yii::getAlias('@app/runtime/crontab/');
 
        @mkdir($lockDir, 0755, true);
 
        $file_lock = fopen($lockDir . $ident, 'w+');
 
        $wouldBlock = 0;
        flock($file_lock, LOCK_EX | LOCK_NB, $wouldBlock);
 
        return $wouldBlock;
    }
}

根據命令列參數產生唯一hash值,代表該PHP任務。

建立鎖定文件,執行flock非阻塞鎖,返回wouldBlock標識鎖是否已被佔用。

我在腳本入口呼叫了Crontab::isRunning()方法,發現並發啟動腳本後,總是能獲得鎖定。

錯誤原因是:isRunning()方法退出後,$file_lock沒有繼續使用,被PHP垃圾回收,$fp檔案句柄關閉導致鎖定自動釋放。

解決

class Crontab
{
    /**
     * 保存起来避免被php作为垃圾回收
     * @var null
     */
    static $file_lock = null;
    /**
     * 确保任务没有并发执行
     */
    public static function isRunning() {
        global $argv;
        $ident = [];
        foreach ($argv as $idx => $value) {
            $ident[] = $idx . '=' . urlencode($value);
        }
        $ident = md5(implode('&', $ident));
        $lockDir = \Yii::getAlias('@app/runtime/crontab/');
        @mkdir($lockDir, 0755, true);
        self::$file_lock = fopen($lockDir . $ident, 'w+');
        $wouldBlock = 0;
        flock(self::$file_lock, LOCK_EX | LOCK_NB, $wouldBlock);
        return $wouldBlock;
    }
}
class Crontab
{
    /**
     * 保存起来避免被php作为垃圾回收
     * @var null
     */
    static $file_lock = null;
 
    /**
     * 确保任务没有并发执行
     */
    public static function isRunning() {
        global $argv;
 
        $ident = [];
        foreach ($argv as $idx => $value) {
            $ident[] = $idx . '=' . urlencode($value);
        }
        $ident = md5(implode('&', $ident));
 
        $lockDir = \Yii::getAlias('@app/runtime/crontab/');
 
        @mkdir($lockDir, 0755, true);
 
        self::$file_lock = fopen($lockDir . $ident, 'w+');
 
        $wouldBlock = 0;
        flock(self::$file_lock, LOCK_EX | LOCK_NB, $wouldBlock);
 
        return $wouldBlock;
    }
}

確保在整個PHP生命期內,檔案句柄都不會被釋放即可,所以保存在類別靜態成員變數裡。

推薦學習:《PHP影片教學

以上是flock php 鎖不成功怎麼辦?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn