Perlでの排他制御(ロック)
[上に]
[前に]
[次に]
satoshi
1998/07/31(金) 12:35:30
Perlでの排他制御(ロック)の話を
http://www.cup.com/negi/tips/flock.html
に書きました。ご意見ご感想を寄せてください。
mo
[E-Mail]
1998/08/03(月) 19:06:16
以前、fj でも話題になりましたが、perl で close 前に flock(FIZ, 8)
でロックを解除すると、思わぬ尾とし穴に引っかかりかねないので
flock(FIZ, 8) は注意したほうがいいです。ちょっと古い perl
(5.003_25 以前だったかな?)の場合はバッファリングのために排他制御
がうまくいかないことがあるからです。よく見かける典型的な誤りは、
open(FIZ, ">>..."); # 出力ファイルを開く
flock(FIZ, 2); # ここから排他処理
seek(FIZ, 0, 2); # 基本 (^^)。ここはこれでよし。
print FIZ, "hello\n";# FIZ に "hello" を出力。でも実際は
# バッファに書き込まれ、ファイルには書き出されない。
flock(FIZ, 8); # ロックを解除、ここまで排他処理
close(FIZ); # ここで初めてファイルに書き出される。
となってしまい、ロック解除後に書き込んでしまうのです。perl 5.004 なら
flock の直前でバッファがフラッシュされ、上記コードで別に何の問題もないで
気にする必要はないです。古い perl も考慮にいれるなら、
open(FIZ, ...);
flock(FIZ, 2);
# do something
close(FIZ);
のように、flock(FIZ, 8) を呼ばないで直接 close するか、あるいは、
open(FIZ, ...);
flock(FIZ, 2);
# do something
$orig = select(FIZ); $| = 1; select($orig);
flock(FIZ, 8);
close(FIZ);
のように、バッファをフラッシュしてからロックオペレーションを
行なったほうがいいです。
とほほ
1998/08/04(火) 00:22:10
今ふと気づいたのですが、flock(FIZ,8); の前に print FIZ ""; と
かの処理を入れなくても大丈夫でしょうか?
satoshi
1998/08/08(土) 23:52:06
おお、ありがとうございます。記述に加えました。
ひろぼー
1998/08/09(日) 21:12:17
ちょっと質問してもいいですか?
チャットや掲示板などで、
以下のような書き込みロック方法をたまに見かけるのですが、
上記を読んで行くと、全く意味がないってことでしょうか?(^^;
open(LOG,">logfile.txt");
flock(LOG,2);
print LOG, "処理結果";
flock(LOG,8);
close(LOG);
flockが紳士協定なら、他のプロセスからロックがかかってても、
flock検査する前にopenしちゃうから、すべて消えちゃう?
B-Cus
1998/08/09(日) 23:49:48
openしたからといって、すぐにファイルに書き込まれるわけでは
ありません。書き込まれるのは、ファイルハンドルにデータを
送って、かつバッファがフラッシュされたときです。
> 上記を読んで行くと、全く意味がないってことでしょうか?(^^;
ですから大丈夫です。
とほほ
1998/08/10(月) 01:47:51
そう言われてみれば、open(LOG, ">logfile.txt"); を実行した時点
で、すでに trancate(LOG, 0);が実行されてしまいそうな気もします
ね。close(LOG)の前にflock(LOG,8);を行うのも問題があるし・・・
open(LOG, ">>logfile.txt");
flock(LOG, 2);
truncate(LOG, 0);
print LOG "処理結果";
close(LOG);
が正しい使用方法なのでしょうか。
mo
[E-Mail]
1998/08/10(月) 15:31:31
いや、
open(LOG, ">logfile.txt");
のままでもいいんじゃないのかな?
これって、C 言語で
fd = open("logfile.txt", O_WRONLY | O_TRANC | O_CREAT);
として実行されますよね。O_WRONLY | O_TRANC の意味って、たしか
「上書きで open した後に、ファイルの長さを 0 にする」
っていうことだったと思いますよ。だから、
> open(LOG,">logfile.txt");
> flock(LOG,2);
を複数のプロセスが同時に呼び出したとしても、ちゃんと排他制御が
行なわれるはずです。
ひろぼー
1998/08/10(月) 19:33:56
実験してみました。確かに排他制御は行われるのですが・・・
【第一プロセス】
open(LOG, ">log.txt");
flock(LOG,2);
print LOG "ABCD\n";
sleep 10;
close(LOG);
【第二プロセス】
open(LOG, ">log.txt");
flock(LOG,2);
print LOG "A\n";
close(LOG);
第一プロセス実行直後に第二プロセスを実行すると、
【log.txt結果】
A
CD
なんてことになりますね。
第二プロセスが open で0バイトにしても、
第一プロセスの close が長さを書き換えてしまう。
やはり truncate が必要なのか・・・
flock が使えて truncate が使えないことってあるのかな?
直接ロックは動作の予測が難しいですね・・・
とほほ
1998/08/10(月) 23:24:42
ロックしていないのに「ファイルの長さを0にする=ファイルの中身を
変更する」とまずいですよね。やはり、truncate()を用いたコードが
正しい用法だと思います。
B-Cus
1998/08/11(火) 00:32:33
> 実験してみました。確かに排他制御は行われるのですが・・・
(snip!)
あら、ほんとだ。確かめずにレスしちゃってごめんなさい。
[上に]
[前に]
[次に]