いつもシンボリックやディレクトリを作って排他制御をしてたんだけど、
phpにはflock()って関数があるので、調べてみました。
●まずは仕様
bool flock(resource handle, int operation)
ファイルをロックします。対象となるハンドルはfopenなどで取得したハンドルを指定します。 引数: handle 対象となるファイルのハンドル operation ロックの方法 返り値: 成功した場合に TRUE、失敗した場合に FALSE
◆ロックの方法は↓
| 値 | 説明 |
|---|---|
| LOCK_SH | 共有ロック ※書込みのみロック |
| LOCK_EX | 排他的ロック ※読み書きロック |
| LOCK_UN | ロック解除 ロックを解除する時に使う |
| LOCK_NB | ロック中にflock()でブロックさせない ※単独で使わず、「LOCK_SH|LOCK_NB」や「LOCK_EX|LOCK_NB」のように”|”で繋いで使う |
●実際に使ってみる
カウンターを作ってみます。 要件: ・実行のたびに、1づつ増える ・ロックのタイムアウトは5秒
<?php
// 変数
$counterFile = './count.dat'; // カウンターファイル
$timeout = 5; // ロックタイムアウト(秒)
// カウンターファイルがあるかフラグ
$counterExists = (file_exists($counterFile) && filesize($counterFile)>0);
// カウンターファイルをオープン
if ($fp=fopen($counterFile, ($counterExists?'r+':'w'))) {
// ロック開始(タイムアウトあり)
do {
if (flock($fp, LOCK_EX|LOCK_NB)) { // ロック成功
// ファイルポインタを先頭に移動
rewind($fp);
// ファイルから読込
$count = $counterExists?fread($fp, filesize($counterFile)):0;
// カウントをインクリメント
++$count;
// ファイルを空にする
ftruncate($fp, 0);
// ファイルポインタを先頭に移動
rewind($fp);
// カウントをファイルに書き込み
fwrite($fp, $count);
// ロック解除
flock($fp, LOCK_UN);
break;
}
--$timeout;
// ロックに失敗したので、まだタイムアウトでなければ1秒待つ
if ($timeout>0) {
sleep(1);
}
} while($timeout);
// ファイルを閉じる
fclose($fp);
}
?>
●使ってみた感想
悪くはないんだけど、今一つ使いにくい気がするなぁ~
ファイルポインタが引数なので、必ずファイルオープンしないといけなかったり、fseekしたりで面倒な感じ…。
もっと上手い使い方があるのかなぁ…。
これからもシンボリックリンクやディレクトリを使って排他制御するかぁ…。