File#flock
web page のカウンタや掲示板のデータが壊れているのって, 見たことない ですか? 昔, 自作のカウンタを付けていたときは, 極たまにゼロにリセットさ れていることがありました. クラックされたってのは考えにくいので, 多分ファ イル操作がうまくいかなくて, データが失われてしまったのかと思います.
こういう「壊れたデータ」を見る機会が増えると, 「計算機でもミスるこ
とがあるんだな」という雰囲気が蔓延してきているように感じるのですが, ちょっ
と待て, 果してそういうものなんでしょうか? 知識として
flock
という関数があることは知ってましたが, 正しい使い方
を知りませんでした. なので, 正しい flock
の使い方を調べて,
それで正しく動くかどうかテストしてみました.
やることは web page のカウンタと同じで, 以下の通りです.
これを, 複数のスレッドで同時に行い, きちんと動作するかを調べます.
上の作業に flock
を加えてもう少し詳しく書くと, 次のように
なります.
r+
) で開くファイルを閉じる前に明示的にアンロックすると, もしファイルに書き出 されていないデータがバッファに残っているときに, マズイことが起こるそう です. もし明示的にアンロックするなら, その前にバッファをフラッシュする 必要があるそうです.
以上を元にして作ってみたスクリプトが, 次のものです.
$number_of_threads
個のスレッドを作り, 各スレッドでは
$number_of_iteration
回だけ数えます. 最終的に表示される数
字が, 両者の積に一致すれば OK. 実行にあまりにも時間がかかるときには,
$number_of_iteration
の数字を減らしてみて下さい.
#!/usr/local/bin/ruby # flock00.rb : test for flock # 1999/12/20 11:28:15 msato # $Id: flock.uhtml,v 1.3 2000-01-04 17:28:36+09 msato Exp $ require 'thread' $fname = 'count.dat' $number_of_threads = 5 $number_of_iteration = 3000 $indent = "\t" def count(num) $number_of_iteration.times do open($fname, "r+") do |f| f.flock(File::LOCK_EX) # <==== lock count = f.gets.to_i + 1 f.rewind f.print count # f.flock(File::LOCK_UN) # <==== unlock $stderr.print $indent * num, count, "\n" end end end begin open($fname, "w") do |f| f.print "0" end rescue $stderr.print "Cannot open #{fname}\n" exit 1 end th = [] 0.upto ($number_of_threads - 1) do |num| th[num] = Thread.start { count(num) } end 0.upto ($number_of_threads - 1) do |num| th[num].value end print "Count = #{$number_of_threads * $number_of_iteration}\n" File::delete($fname)
ファイル操作は count
関数で行ってます. ここの
f.flock(File::LOCK_EX)
や
f.flock(File::LOCK_UN)
をいじって試してみて下さい. 私が試
したところでは, 結果は次の通りでした.
明示的なアンロックをしても動作に問題がなかったのは, データが高々数 バイトという小さなものだったからですかねぇ…
そうそう, 全てのスレッドが終了するまで待つために, ここでは, スレッ
ドが停止するまで待つ Thread#value
を評価しています. 他に
方法はあるのでしょうか?
などと書いておきながら, マニュアルをよく読んで見るとそのものずばり
の Thread#join
を発見 (^^; でも, なんで join なんだろう…
おたより, お待ちしています
sato.mshr@gmail.comCopyright (C) 2000 Masahiro SATO