月度归档:2021年12月

PHP防止重复运行代码

/**
 * 获取当前程序运行了多少个进程
 * @param $processName 程序进程名,要唯一
 */
function GetInstancePids($processName)
{
    // 把文件放到外面去,防止发布版本把状态文件搞没了
    $dir = dirname(dirname(dirname(dirname(__FILE__)))).'/data'.'/pids';
    $file = $dir . DIRECTORY_SEPARATOR . $processName;
    $pinfo = getCurrentProcessInfo();

    if (!file_exists($file)) {
        file_put_contents($file, "{$pinfo['pid']}\t{$pinfo['cmd']}\n");
        return true;
    }

    $i = 0;
    $pidfile = fopen($file, 'r+');
    do {
        if (flock($pidfile, LOCK_EX)) {
            break;
        } else {
            if ($i++ == 10) {
                exit('try 10 times to lock pid file,faild');
            }
            usleep(1000);
        }
    } while (true);

    $read = fread($pidfile, 10240);
    rewind($pidfile);
    $read = explode("\n", trim($read));
    $process_info = [];
    foreach ($read as $index => $line) {
        list($pid, $cmd) = explode("\t", $line);
        if (!empty($pid) && isPidExists($pid, $cmd)) {
            $process_info[] = "{$pid}\t{$cmd}";
        }
    }
    
    $process_info[] = "{$pinfo['pid']}\t{$pinfo['cmd']}";
    ftruncate($pidfile,0);
    fwrite($pidfile, implode("\n", $process_info));
    fflush($pidfile);
    flock($pidfile, LOCK_UN);
    fclose($pidfile);

    return true;
}

/**
 * 返回自身进程信息
 */
function getCurrentProcessInfo()
{
    $mypid = getmypid();
    $outputs = [];
    exec('ps -ax | grep -E "^\s*' . $mypid . '\s+"', $outputs);
    $matched = [];
    preg_match('/^\s*(\S+?)\s+?\S+?\s+?(\S+?)\s+?\S+?\s+?(.+)/', $outputs[0], $matched);
    return [
        'pid' => $matched[1],
        'uptime' => $matched[2],
        'cmd' => $matched[3],
    ];
}

function isPidExists($pid, $cmd)
{
    exec('ps -ax | grep -E "^\s?'. $pid . '.+?'.$cmd.'"', $result);
    return isset($result[0]);
}

 

使用的时候:

$pids = GetInstancePids(“xxx”);
if (count($pids) > 1) die(“程序运行中”);