ホームページを公開する場合、不特定多数の人が訪れることが前提となります。(中にはそうでない場合もありますが)
また、不特定多数の人が同時に同じページにアクセスすることも考えられます。
そんな中で動くCGIでは、同時に同じファイルにアクセスしてしまうと、正しいデータが作成できなかったり
ひどい場合、ファイルを破壊することもあります。
この問題を回避する方法が、排他制御です。
排他制御が無い場合の例(カウンター):
| プロセスA | プロセスB |
|---|---|
| ファイルのopen | |
| カウント値を読み込む(値:9) | ファイルのopen |
| カウントアップ(値:9->10) | カウント値を読み込む(値:9) |
| ファイルに書き込む(値:10) | カウントアップ(値:9->10) |
| ファイルのclose | ファイルに書き込む(値:10) |
| ファイルのclose |
上記例では、プロセスBが終了時にカウント値は11になっていないといけないのですが、読み書きのタイミングにより
10のままになっています。
また、ファイルではなくデータベースを使っている場合でも同じようなことが起きます。
これもまた、回避方法が存在します。
さて、排他制御の流れをみてみます。
| プロセスA | プロセスB |
| 排他(ロック)する | |
| ファイルのopen | |
| カウント値を読み込む(値:9) | ロックされている為、ファイルのopenできない |
| カウントアップ(値:9->10) | ロック解除待ち |
| ファイルに書き込む(値:10) | ロック解除待ち |
| ファイルのclose | ロック解除待ち |
| ロック解除 | ロック解除待ち |
| 排他(ロック)する | |
| ファイルのopen | |
| カウント値を読み込む(値:10) | |
| カウントアップ(値:10->11) | |
| ファイルに書き込む(値:11) | |
| ファイルのclose | |
| ロック解除 |
最も簡単な排他制御です。しかし、flock()関数はOSによっては機能しない場合があります。
ターゲットが固定的で明らかに使用可能な場合のみ使用します。
サンプル:
<?php
$fp = @fopen(""/counter/cnt.dat", "r+");
//念のため(いるのかな?)
set_file_buffer($fp, 0);
rewind($fp);
//
flock($fp, LOCK_EX);
$cnt = fgets($fp);
if(!$cnt) {
$cnt = 1;
}
else {
$cnt++;
}
rewind($fp);
fputs($fp, $cnt);
flock($fp, LOCK_UN);
fclose($fp);
?>
エラー処理などははぶいてしまっていますが、ファイルをオープンした後にset_file_buffer()関数で
書き込み時のバッファリングをしないように設定しています。
次に、本題の排他制御です。flock()関数を使って排他的ロックをするには、ファイルポインタとLOCK_EXを
指定します。
カウントアップと書き込み処理が終了した時点で、ロックを解除します。
ロックの解除にも、flock()関数を使います。ロックを解除するには、ファイルポインタとLOCK_UNを
指定します。
最後にファイルをcloseすれば終了です。
Copyright 1997-2008 BBB All rights reserved.