>백엔드 개발 >PHP 문제 >Flock PHP 잠금이 실패하면 어떻게 해야 합니까?

Flock PHP 잠금이 실패하면 어떻게 해야 합니까?

藏色散人
藏色散人원래의
2021-11-08 09:32:402242검색

flock PHP 잠금 실패는 isRunning() 메서드가 종료된 후 $file_lock이 사용되지 않아 발생합니다. 해결 방법은 전체 PHP 수명 주기 동안 파일 핸들이 해제되지 않도록 하는 것입니다.

Flock PHP 잠금이 실패하면 어떻게 해야 합니까?

이 기사의 운영 환경: Windows 7 시스템, PHP 버전 7.1, DELL G3 컴퓨터

PHP 잠금에 실패하면 어떻게 해야 합니까?

PHP 무리 실패 문제에 대한 솔루션:

지난 이틀 동안 저는 crontab에서 예약한 PHP 스크립트의 동시 실행을 방지하기 위한 사이드 프로젝트용 메서드를 작성했습니다.

방법

일반적으로 파일 잠금 무리 방식을 사용하면 동일한 PHP 스크립트가 동일한 디스크 파일을 비차단적으로 잠그므로 해당 파일이 사용 중이면 오류가 보고되므로 스크립트가 작동할 수 있습니다. 즉시 퇴장하세요.

현상

실제로는 컨트롤러 파일에서 직접 Flock이 가능하다는 것을 알 수 있는데 Flock의 로직을 다른 파일의 함수에 캡슐화하면 무효가 됩니다.

Cause

오랜 시간 동안 디버깅을 하다가 문득 예전에 이런 함정에 부딪힌 적이 있다는 생각이 들었습니다. .

오류 코드는 다음과 같습니다.

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;
    }
}

PHP 작업을 나타내는 명령줄 매개변수를 기반으로 고유한 해시 값을 생성합니다.

잠금 파일을 생성하고, 무리 비차단 잠금을 실행하고, wouldBlock을 반환하여 잠금이 점유되었는지 확인합니다.

스크립트 항목에서 Crontab::isRunning() 메서드를 호출했는데 스크립트를 동시에 시작한 후에는 항상 잠금을 얻을 수 있다는 것을 발견했습니다.

오류의 원인은 isRunning() 메서드가 종료된 후 $file_lock이 더 이상 사용되지 않고 PHP에 의해 가비지 수집되기 때문입니다. $fp 파일 핸들이 닫혀 잠금이 자동으로 해제됩니다.

Solution

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으로 문의하세요.