ホームページを公開する場合、不特定多数の人が訪れることが前提となります。(中にはそうでない場合もありますが)
また、不特定多数の人が同時に同じページにアクセスすることも考えられます。
そんな中で動く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-2010 BBB All rights reserved.