PHPのflock関数を使って排他処理を行う方法を紹介しています。
Webアプリでは、複数のプロセスが同時に実行されますが、処理によっては競合してしまいエラーとなるものもあります。
そういった時に、flock関数のファイルロックする機能を利用して、同時に処理が行われないよう実装します。
基本的には次のような流れで処理を行います。
ロックモードは次のものが指定できます。
定数 | 説明 |
---|---|
LOCK_SH | 共有ロック。ロックされていた場合は解除されるまで待つ。 |
LOCK_EX | 排他的ロック。ロックされていた場合は解除されるまで待つ。 |
LOCK_UN | ロックを解除。 |
LOCK_SH | LOCK_NB | 共有ロック。ロックされていた場合はfalseを返す。(Windowsではサポートされない。) |
LOCK_EX | LOCK_NB | 排他的ロック。ロックされていた場合はfalseを返す。(Windowsではサポートされない。) |
LOCK_NBはWindowsではサポートされていませんが、試したところ使えました。
なぜでしょう。。。
まずは普通にファイルロックを使用して、複数アクセス時にも処理が被らないようにします。
$lock=$this->start_lock();
~処理~
fclose($lock);
function start_lock()
{
$lock = 'hoge.lock';
if (!$fp=fopen($lock, "a")) die("can't lock");
flock($fp, LOCK_EX);
return $fp;
}
グループ化してロックしたい場合は、ロックモードを使い分けて行います。
//一つ目の処理
$lock=start_lock4();
$lock_wait=start_lock();
fclose($lock_wait);
~処理~
fclose($lock);
//二つ目の処理
$lock=start_lock4();
$lock_wait=start_lock();
fclose($lock_wait);
~処理2~
fclose($lock);
//三つ目の処理
$lock=start_lock2();
$lock_wait=start_lock3();
fclose($lock_wait);
~処理3~
fclose($lock);
function start_lock()
{
$lock = 'hoge.lock';
if (!$fp=fopen($lock, "a")) die("can't lock");
flock($fp, LOCK_EX);
return $fp;
}
function start_lock2()
{
$lock = 'hoge.lock';
if (!$fp=fopen($lock, "a")) die("can't lock");
flock($fp, LOCK_SH | LOCK_NB);
return $fp;
}
function start_lock3()
{
$lock = 'hoge2.lock';
if (!$fp=fopen($lock, "a")) die("can't lock");
flock($fp, LOCK_EX);
return $fp;
}
function start_lock4()
{
$lock = 'hoge2.lock';
if (!$fp=fopen($lock, "a")) die("can't lock");
flock($fp, LOCK_SH | LOCK_NB);
return $fp;
}
一つ目と二つ目の処理をグループ化してみました。
う~ん。。。微妙ですね。。。w