flock php鎖定不成功是因為在isRunning()方法退出後,$file_lock沒有繼續使用導致的,其解決方法就是確保在整個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中文網其他相關文章!