PHP MySQL获取锁定

PHP MySQL获取锁定,php,mysql,locking,Php,Mysql,Locking,在一个脚本中,我试图使用MySQLGET\u LOCK检查同一个脚本是否已经在运行。问题是,当脚本尝试获取锁时(锁不是免费的),无论我提供的参数是什么,它都会永远阻塞 <?php class Controller_Refresher extends Controller { public function action_run($key) { echo date('H:i:s'."\n", time()); $this->die_if_run

在一个脚本中,我试图使用MySQL
GET\u LOCK
检查同一个脚本是否已经在运行。问题是,当脚本尝试获取锁时(锁不是免费的),无论我提供的参数是什么,它都会永远阻塞

<?php

class Controller_Refresher extends Controller {
    public function action_run($key) {
        echo date('H:i:s'."\n", time());
        $this->die_if_running();
        $this->run();
        echo date('H:i:s'."\n", time());
    }

    private function die_if_running() {
        $result = DB::query(Database::SELECT, "SELECT IS_FREE_LOCK('refresher_running') AS free")->execute();
        if (! intval($result[0]['free'])) die('Running already');
        $result = DB::query(Database::SELECT, "SELECT GET_LOCK('refresher_running', 1)")->execute();
    }

    private function run() {
        echo "Starting\n";
        ob_flush();
        sleep(10);

        DB::query(Database::SELECT, "SELECT RELEASE_LOCK('refresher_running')")->execute();
    }
}

而我想做的是让第二个选项卡
die('Running ready')

一种选择是依赖文件系统锁而不是数据库。因为需要处理的是脚本执行,所以这不重要。具有非阻塞独占锁的来自的示例:

$fp = fopen('/tmp/lock.txt', 'r+');

/* Activate the LOCK_NB option on an LOCK_EX operation */
if(!flock($fp, LOCK_EX | LOCK_NB)) {
    die('Running already');
}

/* ... */

fclose($fp);

编辑

另一种选择是使用在每次执行开始时创建的状态文件,该文件将在脚本完成时自动删除

脚本只需检查状态文件是否存在,如果它已经存在,执行将停止:

define('statusFile', sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'myjob.running');

//
// If a process is already running then exit
//
if (file_exists(statusFile)) {
   die('Running already');
} else {
   file_put_contents(date('Y-m-d H:i:s'), statusFile);
}

//
// Other code here
//

function shutdown() {
   unlink(statusFile);
}

//
// Remove the status file on completion
//
register_shutdown_function('shutdown');

注意-此问题实际上可能是由php锁定会话文件引起的:

因此,您应该在需要并发运行的任何代码之前调用session_write_close()。我在尝试这个互斥类后发现:

这个课程做得很好,但是我的php脚本仍然在一个接一个地运行

此外,您不需要IS_FREE_LOCK()。只需调用GET_LOCK('refresher_running',0),如果它给了您锁,它将返回1,如果锁被占用,它将返回0。那样更原子化。当然,锁定超时在某些情况下仍然很有用,比如当您想对任务排队时,但是如果您同时收到太多请求,请注意脚本超时


扎克·莫里斯

@roddik:如果
flock
失败,则可以手动实现相同的功能。@roddik:True。在Windows上检测异常终止是困难的,但它是可行的。例如,通过不断更新状态文件内的时间戳以指示继续执行,过时的状态文件显示异常终止。
define('statusFile', sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'myjob.running');

//
// If a process is already running then exit
//
if (file_exists(statusFile)) {
   die('Running already');
} else {
   file_put_contents(date('Y-m-d H:i:s'), statusFile);
}

//
// Other code here
//

function shutdown() {
   unlink(statusFile);
}

//
// Remove the status file on completion
//
register_shutdown_function('shutdown');