がるの健忘録

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

「バッチファイルの二重起動の防ぎ方」PHP変

時々(あるいはしょっちゅう)あるのですが、バッチファイルが「二重に動くと吾妻しくねぇなぁ」な状況があります。
よくロックファイルによる二重起動防止とかを見るのですが…もうちょっと楽な手段があるので、まぁ「カードの一枚」程度に。


機構としては、至極一般的な「セマフォ」を使います。
セマフォは「プロセス間通信」の一環になります。…それ以上を知りたかったら、C言語系の書籍を適宜あたってくださいませ。
…そのうち解説するかもしんまい。リクエストはコメントもしくはリアルで直接どんぞ。


閑話休題


サンプルコードから、早速かつとっとと実装をまなんでみませう。
まずは「ロックされていない」状態を体感して確認。
バッチファイルはこんな感じ。ファイル名は「t.php」という、素晴らしく投げたネーミング。

// 処理
$pid = posix_getpid();
//
print "start({$pid}) \n";
sleep(5);
print "end({$pid}) \n";

わかりやすい感じでひとつ。startってデバッグ出力してから、sleep5がきっと「色々なバッチ処理」。endもデバッグ出力的な感じ?
…あ、sleep5秒は、短いようで微妙に長いんで。いらいらしたら、適当に数字を入れ替えてください。


この子をあえて「ほぼ同時に」叩きます。
こんなファイルを用意。テストなんで、おいちゃんはこのファイル名を「ttt」としました。

php t.php &
php t.php &
php t.php &
php t.php &
php t.php &


これを実行してみます。

sh ttt
[gallu:~]start(10228)
start(10231)
start(10227)
start(10229)
start(10230)
end(10228)
end(10227)
end(10231)
end(10229)
end(10230)

排他制御もへったくれもありません。
では、セマフォで排他してみましょう。

// セマフォを取得
$sobj = sem_get(123);
$r = sem_acquire($sobj);

// 処理
$pid = posix_getpid();
//
print "start({$pid}) \n";
sleep(5);
print "end({$pid}) \n";

// セマフォを解放
sem_release($sobj);


たった三行で、ほらこのとおり。

sh ttt
[gallu:~]start(10353)
end(10353)
start(10351)
end(10351)
start(10352)
end(10352)
start(10355)
end(10355)
start(10354)
end(10354)

OSの「微妙なプロセスIDのふりかた」は気にせずに。
ちなみに、丁寧に sem_release してますが、基本、上述のコードなら不要です。

// セマフォを取得
$sobj = sem_get(123);
$r = sem_acquire($sobj);

// 処理
$pid = posix_getpid();
//
print "start({$pid}) \n";
sleep(5);
print "end({$pid}) \n";


実行結果

sh ttt
start(10515)
[gallu:~]end(10515)
start(10517)
end(10517)
start(10516)
end(10516)
start(10518)
end(10518)
start(10519)
end(10519)


こんな感じ。


昨日、勉強会っていうかぶっちゃけ「開発合宿もどき」で、うちの子たちが知らんかったので、備忘録かねて。