一回も披露したことのない豆知識

たいていの場合は問題ないのですが、
アクセスカウンタ等の更新の激しい物の場合、
file()やfile_get_contents()でファイルを開き、
その内容を元にfopen()・flock()・fputs()等を使って書き込むと、
データが破損してしまう事があります。
これはロック中でもfile()等では開けてしまうのが原因だと思いますが、
file()等を使う際の排他処理はどのようにしたら良いのでしょうか。


ロック中は、fopen()の前で解放されるのを待つ仕様なようなので、

$fp=fopen("ロック用ファイル","r");
flock($fp,LOCK_EX);
~複数のファイルの読み書きを含めた、様々な処理~
fclose($fp);

としてみたのですが、これで排他処理は完璧になるでしょうか?


これまでは、

1. ロック用ファイルが存在する場合、なくなるまでsleep()
2. 空のロック用ファイルを作成
~複数のファイルの読み書きを含めた、様々な処理~
3. ロック用ファイルを削除

としていたのですが、これでは度々破損してしまいました。
「1」と「2」の間で、新しいプロセスが「1」に割り込んで来てしまうせいでしょうか。
そうだとすれば、fopen()とflock()の間でも
同じ事が起きてしまう気がするのですが、どうなんでしょうか。

A 回答 (2件)

おや?だめですか?


では「大人のCGIスクリプト」という本で紹介されていた方法
ファイルが飛ばないようにするには
:ダブルファイルを用いて、両方の更新時間を比較
:更新時間の新しい方のデータを読んで、古い方に書き込む
:よって、データは交互に書き込まれる。
カウンターなら、これだけでもデータが飛ばなくなる
とありました。
あと、以前のQAで、一時ファイルに書き込んでからrenameを使う方法が紹介されてました。
掲示板用ならこちらがよいかもしれません。
http://oshiete1.goo.ne.jp/kotaeru.php3?q=1677355

それでもかち合うアクセス数は私にはイメージが付かないので、参考にならないかもしれませんが。

シグナルについてはphpでは、このへんかな?
pcntl_signal -- シグナルハンドラを設定する
http://www.php.net/manual/ja/ref.pcntl.html
お使いのサーバーで有効になってるかどうかも調査する必要がありそうです。

この回答への補足

ご丁寧に有り難う御座います。
今のところはロック用ファイルを用意して、それをflock()する事で破損を防げているようです。
土日に破損する事が多いので、もう少し様子見してみようと思います。

ご教授頂いた交互に書き込む方法も良さそうですね。
ただ、この方法だけでは複数のプロセスで同じデータを扱ってしまう可能性があり、
結局は別途に排他処理を行う必要がありますね。
rename()も同じでファイルを開く際に別途ロックを行わなければいけませんね。

シグナルの件ですが、素人の私には結構難しそうです^^;
色々もっと勉強しないといけないみたいです。
でも、モジュール版ではその関数は使えないようですので、関係ないようですね。
有り難う御座いました。

補足日時:2006/03/14 11:15
    • good
    • 0
この回答へのお礼

時間が空いてしまい、申し訳御座いません。
結局、先週の土曜日に破損してしまいました。
見た目、flock()を使った方法に問題は見受けられないんですが・・・。
フラグが残ってしまった場合の対応が曖昧ですが、とりあえずmkdir()も加えてみようと思います。
トップページで使用しているため、出来ればsleepは避けたい気持ちがあるのですが・・・

お礼日時:2006/03/21 00:23

symlinkかmkdirの方がよいそうです。


参考 web と CGI のひみつ >> 排他処理
http://x68000.q-e-d.net/~68user/webcgi/lock.html

参考URL:http://x68000.q-e-d.net/~68user/webcgi/lock.html
    • good
    • 0
この回答へのお礼

アドバイス有り難う御座います。
これまでにPerlカウンタ等でmkdir()やsymlink()を使っていたのですが、
それでも度々データが破損してしまいました。
参考サイト様によると、シグナルが原因のようですが、
これはモジュール版PHPでも言える事なのでしょうかね。
mkdir()やsymlink()を使った時に
フラグが残ったままになってしまった場合の処理方法がよく分かりません。
単にsleep(1)を5回繰り返してダメならフラグ削除、というのでは問題アリだと思うので。

お礼日時:2006/03/13 07:06

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!