ファイルの排他制御について

いつもシンボリックやディレクトリを作って排他制御をしてたんだけど、
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したりで面倒な感じ…。
もっと上手い使い方があるのかなぁ…。
これからもシンボリックリンクやディレクトリを使って排他制御するかぁ…。

コメントを残す

メールアドレスが公開されることはありません。