がるの健忘録

エンジニアでゲーマーで講師で占い師なおいちゃんのブログです。

phpでざっくりアドバイザリロック

いわゆる排他制御系。
いやまぁおいちゃん的には「セマフォ使えばいいじゃない終了」で終わるお話なんですが。
PHPセマフォ、一応「コンパイルで指定が必要(coreじゃない)」ので、稀に、極稀に「入ってない環境」とかあるので……いやまぁ「入れろ」って話なんですが。
・多重度1のみ
限定条件だと、まぁ「ファイルによるロック」は色々論外なのですが、もう1つ方法があるよねぇ、ってんで、アドバイザリロック。

端的には「バッチファイル自身を排他ロック」するやりかたで、これなら「バッチが異常終了」しても「プロセス落ちたからロックが外れる」ので、割と面倒が少のうございます。

実装もシンプルなのですが、まぁとどのつまり「実装してみたかった」ので、実装してみます。
なお本記事には「アドバイザリロックって単語をちょいちょい忘れるから備忘録用に記録している」わけではないことを初めに言い訳しておきます。

本題。

まずアドバイザリロックのコード本体は、こんな感じ。
AdvisoryLock.php

<?php
declare(strict_types=1);
function advisoryLock(string $filename) : bool
{
    // ここ、staticにしないと関数ぬけたらインスタンスがGCに行くからファイルcloseされちゃう
    static $file;
    //
    try {
        //
        $file = new SplFileObject($filename);
        if (false === $file->flock(LOCK_EX | LOCK_NB)) {
            return false;
        }

    } catch (\Throwable $e) {
        echo $e->getMessage();
        return false;
    }

    return true;
}

実験用のファイル。
AdvisoryLockExec.php

AdvisoryLockExec2.php
(中身は一緒)

<?php
declare(strict_types=1);
include('./AdvisoryLock.php');

$pid = __FILE__ . ':' . getmypid();
if (false === advisoryLock(__FILE__)) {
    echo "{$pid}  NG\n";
    exit;
}

sleep(3);
echo "{$pid}  ok\n";

で、一応実験。

[gallu@a.b.c.d ~]$ php AdvisoryLockExec.php & php AdvisoryLockExec.php & php AdvisoryLockExec.php & php AdvisoryLockExec2.php & php AdvisoryLockExec2.php & php AdvisoryLockExec2.php
[1] 2272
[2] 2273
[3] 2274
[4] 2275
[5] 2276
/home/gallu/AdvisoryLockExec2.php:2277 NG
/home/gallu/AdvisoryLockExec2.php:2275 NG
[gallu@ik1-315-17990 ~]$ /home/gallu/AdvisoryLockExec.php:2273 NG
/home/gallu/AdvisoryLockExec.php:2274 NG
/home/gallu/AdvisoryLockExec2.php:2276 ok
/home/gallu/AdvisoryLockExec.php:2272 ok

[1] 終了 php AdvisoryLockExec.php
[2] 終了 php AdvisoryLockExec.php
[3] 終了 php AdvisoryLockExec.php
[4]- 終了 php AdvisoryLockExec2.php
[5]+ 終了 php AdvisoryLockExec2.php
[gallu@a.b.c.d ~]$

まぁ、予想通りの期待通り。

まぁ「素直にセマフォにしとこうぜ」とか思うんですが、別解で「これならギリギリ」ってんで、軽めに。