ファイルのロックについて教えてください
山本伸也
1999/09/28(火) 13:07:04
ファイルロックについて質問です。
スクリプト内でファイルを編集するとき、
基本的に以下のようにしています。
# 排他制御開始
open(LOCK, "$file");
flock(LOCK, 2);
# ログの読み込み
open(LOG, "$logfile");
@log = <LOG>;
close(LOG);
# 処理
・・・・・・
# ログの書き込み
open(LOG, ">$logfile");
print LOG @log;
close(LOG);
# 排他制御終了
close(LOCK);
つまり、最初と最後で関係ないファイルをロック専用に
使っているのです。
例ではログ・ファイルだけですが、実際にはカウンタなど複数の
ファイルを編集しています。
しかし、頭の中では完璧だと思っていたのですが、
カウンタ・ファイルなどがたまに失敗して壊れてしまいます。
この方法に間違いがあるのでしょうか?
ファイルロックについて質問です。
スクリプト内でファイルを編集するとき、
基本的に以下のようにしています。
# 排他制御開始
open(LOCK, "$file");
flock(LOCK, 2);
# ログの読み込み
open(LOG, "$logfile");
@log = <LOG>;
close(LOG);
# 処理
・・・・・・
# ログの書き込み
open(LOG, ">$logfile");
print LOG @log;
close(LOG);
# 排他制御終了
close(LOCK);
つまり、最初と最後で関係ないファイルをロック専用に
使っているのです。
例ではログ・ファイルだけですが、実際にはカウンタなど複数の
ファイルを編集しています。
しかし、頭の中では完璧だと思っていたのですが、
カウンタ・ファイルなどがたまに失敗して壊れてしまいます。
この方法に間違いがあるのでしょうか?
M.Nakawaki
[E-Mail]
[HomePage]
1999/09/28(火) 20:51:04
flockを使うんでしたら余計なロックファイルなどを作らずに
open(DAT,"+< $log");
flock(DAT, 2);
truncate(DAT, 0);
seek(DAT, 0, 0);
print DAT @edit;
close(DAT);
でOKですよ。
あなたが書かれた方法だとロックは掛かっていないと思います。
この例の方法のロックのほうがシムリンクを使う方法よりも
強固ですけど何をやってもログが飛ぶ時は飛びます(苦笑)
このflockについては過去ログでflockとすれば大量に出てきますよ。
そちらを見て下さい。
flockを使うんでしたら余計なロックファイルなどを作らずに
open(DAT,"+< $log");
flock(DAT, 2);
truncate(DAT, 0);
seek(DAT, 0, 0);
print DAT @edit;
close(DAT);
でOKですよ。
あなたが書かれた方法だとロックは掛かっていないと思います。
この例の方法のロックのほうがシムリンクを使う方法よりも
強固ですけど何をやってもログが飛ぶ時は飛びます(苦笑)
このflockについては過去ログでflockとすれば大量に出てきますよ。
そちらを見て下さい。
M.Nakawaki
1999/09/28(火) 20:57:26
余談ですけど、回数のみを記録すればいい単純な
カウンターの場合は
open(DAT,">>$log");
print DAT "\n";
close(DAT);
と追記モードで「改行文字(1バイト)」のみを書き込んでいって
カウント数はバイト数を
$count = -s "$log";
で得ればまずログが飛ぶことはないです。(ログをゼロクリアしていませんので)
余談ですけど、回数のみを記録すればいい単純な
カウンターの場合は
open(DAT,">>$log");
print DAT "\n";
close(DAT);
と追記モードで「改行文字(1バイト)」のみを書き込んでいって
カウント数はバイト数を
$count = -s "$log";
で得ればまずログが飛ぶことはないです。(ログをゼロクリアしていませんので)
山本伸也
1999/10/01(金) 00:49:04
Nakamakiさん、遅ればせながらありがとうございます。
しかし、まだ分からないことがあるのです・・・
ロックの話題はもういい、と思う方も多いと思いますが、どうか聞いてください。
まず、Nakamakiさんのseekを使う方法が定石なのは十分理解できるのですが、
私が最初の発言で示した方法がなぜ失敗するのか、どうしても理解できないのです。
ロック専用ダミーファイルで入り口を閉めておけば十分だと思うのですが・・・
もちろん、完璧な方法がないのは分かってます。でも、私の方法は「ロック」
されていないのでしょうか?
実は、どうしても「入り口で一回ロックして、出口で解放」という方法を
実現したいのです。
mkdirを使う方法もありますが、その場合パーミッションを707にしなくては
ならないため、危険が伴うと思います。
何か手はないでしょうか?
Nakamakiさん、遅ればせながらありがとうございます。
しかし、まだ分からないことがあるのです・・・
ロックの話題はもういい、と思う方も多いと思いますが、どうか聞いてください。
まず、Nakamakiさんのseekを使う方法が定石なのは十分理解できるのですが、
私が最初の発言で示した方法がなぜ失敗するのか、どうしても理解できないのです。
ロック専用ダミーファイルで入り口を閉めておけば十分だと思うのですが・・・
もちろん、完璧な方法がないのは分かってます。でも、私の方法は「ロック」
されていないのでしょうか?
実は、どうしても「入り口で一回ロックして、出口で解放」という方法を
実現したいのです。
mkdirを使う方法もありますが、その場合パーミッションを707にしなくては
ならないため、危険が伴うと思います。
何か手はないでしょうか?
山本伸也
1999/10/01(金) 00:51:42
補足です・・・
パーミッションを707にというのは、もちろんCGIの設置ディレクトリ
のことです。当方のプロバはCGIがnobodyで動くので。
補足です・・・
パーミッションを707にというのは、もちろんCGIの設置ディレクトリ
のことです。当方のプロバはCGIがnobodyで動くので。
Nobu3
[E-Mail]
[HomePage]
1999/10/01(金) 01:00:46
落ち着いて考えてみましょう。flockの動作を。
flockはハンドラにかけるものでしょう?
つまり、最初のサンプルだと「LOCK」にロックがかかっているんではないですか?
だから、それ以外の「LOG」などはロックされていない。
解釈が違ってますか?
落ち着いて考えてみましょう。flockの動作を。
flockはハンドラにかけるものでしょう?
つまり、最初のサンプルだと「LOCK」にロックがかかっているんではないですか?
だから、それ以外の「LOG」などはロックされていない。
解釈が違ってますか?
山本伸也
1999/10/01(金) 01:22:11
でも、先のプロセスがLOGをイジっている間、LOCKがロックされているので、
次に来たプロセスはLOGをイジれないと思うのですが・・・
どうでしょうか?
>flockはハンドラにかけるものでしょう?
>つまり、最初のサンプルだと「LOCK」にロックがかかっているんではないですか?
>だから、それ以外の「LOG」などはロックされていない。
でも、先のプロセスがLOGをイジっている間、LOCKがロックされているので、
次に来たプロセスはLOGをイジれないと思うのですが・・・
どうでしょうか?
Nobu3
[E-Mail]
[HomePage]
1999/10/01(金) 02:24:31
う・・・。なるほど・・・。
そうですね。
落ち着いて考えると、僕が理解してなかったみたいです。
すいません。
う・・・。なるほど・・・。
そうですね。
落ち着いて考えると、僕が理解してなかったみたいです。
すいません。
山本伸也
1999/10/01(金) 10:18:59
やはりロックはかかりますよね?
でも、頻繁にカウンタが壊れるんです。
これはほかに原因があるのかなぁ・・・
やはりロックはかかりますよね?
でも、頻繁にカウンタが壊れるんです。
これはほかに原因があるのかなぁ・・・
通りすがりの者
1999/10/01(金) 12:19:08
ロックをかけなければ、ファイルが壊れることがある。(本当)
ロックをかければ、ファイルは壊れない。(嘘)
を行った時点でファイルのサイズは0になりますよね。ここで、
を行う前に、メモリ不足やディスク溢れなどの理由でプログラムが
停止すると・・・・見事にファイルは壊れてしまいます。
ロックをかけなければ、ファイルが壊れることがある。(本当)
ロックをかければ、ファイルは壊れない。(嘘)
> open(LOG, ">$logfile");
を行った時点でファイルのサイズは0になりますよね。ここで、
> print LOG @log;
を行う前に、メモリ不足やディスク溢れなどの理由でプログラムが
停止すると・・・・見事にファイルは壊れてしまいます。
エキストラ
1999/10/01(金) 16:16:16
壊れるならバックアップ取るしかないね(テキトー)
けどログなら読み終わった後に一度閉じて『追記』じゃだめなのかな?
壊れるならバックアップ取るしかないね(テキトー)
けどログなら読み終わった後に一度閉じて『追記』じゃだめなのかな?
hirao
[E-Mail]
1999/10/02(土) 03:44:47
サーバーのでのファイルの扱いってどうなっているのでしょうかね…?
その辺で詳しい人に教えてもらわないと分からないですね。
とりあえずすべてのファイルをちゃんとflockするやつを試験的に作っ
てみてそれでどうか試してみるといいのでは…? 手間がかかりますが
勉強になりますので、flock関係の部分をサブルーチンにすればそれほ
ど手間はかからないと思いますので…
とりあえず推測としては、ファイルの読込って、ディスクの物を読み
込むのか、メモリーのキャッシュの物を読み込むのかその辺がどうなっ
ているのでしょうね…? 他のプロセスがキャッシュの物を読み込むの
であれば問題ないですが、ディスクの物を読み込むのであれば問題にな
りますよね…? 容量の少ないロック用のファイルが、一瞬でcloseさ
れてしまってもLOGファイルの方は書込に時間がかかってしまいますか
ら、flockで待っていたプロセスは書込中のLOGをアクセスすることに…
openと同時にファイルが0になるのなら、それを読み込む確率が高く
なっているのでは? LOGの書込が終わってcloseされて正常に読み込め
るわけで… openで一段階ですのでそこでキャッシュ上のファイルは0
に… ディスク書込中に他で読み込めるかは謎ですが読み込めたとして
もcloseされていない不完全な物になります。読み込めないとすると
openされた直後の0のファイルになります。
もし上記の推測があたっているとすると、flockの無い物より、open
直後のファイルを読み込む確率の高い物になってしまっています
(^^;;; 逆効果です、flockによってシンクロされてしまっています。
あと、メモリー上のデーター(キャッシュ)にしてもそのプロセスで
の固有のデーターが他のプロセスでも読めるデーターに変わるタイミン
グが、ロック用のファイルのロックが解かれるよりも早くに行われるの
かは謎ですよね…?
サーバーのでのファイルの扱いってどうなっているのでしょうかね…?
その辺で詳しい人に教えてもらわないと分からないですね。
とりあえずすべてのファイルをちゃんとflockするやつを試験的に作っ
てみてそれでどうか試してみるといいのでは…? 手間がかかりますが
勉強になりますので、flock関係の部分をサブルーチンにすればそれほ
ど手間はかからないと思いますので…
とりあえず推測としては、ファイルの読込って、ディスクの物を読み
込むのか、メモリーのキャッシュの物を読み込むのかその辺がどうなっ
ているのでしょうね…? 他のプロセスがキャッシュの物を読み込むの
であれば問題ないですが、ディスクの物を読み込むのであれば問題にな
りますよね…? 容量の少ないロック用のファイルが、一瞬でcloseさ
れてしまってもLOGファイルの方は書込に時間がかかってしまいますか
ら、flockで待っていたプロセスは書込中のLOGをアクセスすることに…
openと同時にファイルが0になるのなら、それを読み込む確率が高く
なっているのでは? LOGの書込が終わってcloseされて正常に読み込め
るわけで… openで一段階ですのでそこでキャッシュ上のファイルは0
に… ディスク書込中に他で読み込めるかは謎ですが読み込めたとして
もcloseされていない不完全な物になります。読み込めないとすると
openされた直後の0のファイルになります。
もし上記の推測があたっているとすると、flockの無い物より、open
直後のファイルを読み込む確率の高い物になってしまっています
(^^;;; 逆効果です、flockによってシンクロされてしまっています。
あと、メモリー上のデーター(キャッシュ)にしてもそのプロセスで
の固有のデーターが他のプロセスでも読めるデーターに変わるタイミン
グが、ロック用のファイルのロックが解かれるよりも早くに行われるの
かは謎ですよね…?
B-Cus
1999/10/02(土) 04:28:17
一般的に、NFS 環境下では flock は使えません。
そーゆーときは、耐久試験をするの。例えばロック・追加部分を
test というスクリプトにまとめて、
% perl -e 'for (1..10){system("./test&")}}'
とか。同時に10プロセスが書き込んだくらいで壊れるようなら
flock は使えないんでしょう。mkdir や symlink を使いましょう。
ただしこういう実験でミスると、下手したらサーバが落ちますので
慎重に。共用サーバなら、負荷の低い朝方などに 5個くらいの
プロセスで試しましょう (これもあまり勧められないけどさ)。
# 僕も最初
# % perl -e 'for (1..10){if(fork){system("echo $_")}}'
# ってやっちゃって、プロセス大爆発。プロセスの上限数が越えてて
# kill も su も実行できない。あせった。
推測に過ぎませんけど、そういう根本的な問題はないんじゃない?
だってそういうのが起こるなら、欠陥 OS だから。
一般的に、NFS 環境下では flock は使えません。
> でも、頻繁にカウンタが壊れるんです。
> これはほかに原因があるのかなぁ・・・
そーゆーときは、耐久試験をするの。例えばロック・追加部分を
test というスクリプトにまとめて、
% perl -e 'for (1..10){system("./test&")}}'
とか。同時に10プロセスが書き込んだくらいで壊れるようなら
flock は使えないんでしょう。mkdir や symlink を使いましょう。
ただしこういう実験でミスると、下手したらサーバが落ちますので
慎重に。共用サーバなら、負荷の低い朝方などに 5個くらいの
プロセスで試しましょう (これもあまり勧められないけどさ)。
# 僕も最初
# % perl -e 'for (1..10){if(fork){system("echo $_")}}'
# ってやっちゃって、プロセス大爆発。プロセスの上限数が越えてて
# kill も su も実行できない。あせった。
> とりあえず推測としては、ファイルの読込って、ディスクの物を読み
> 込むのか、メモリーのキャッシュの物を読み込むのかその辺がどうなっ
> ているのでしょうね…?
推測に過ぎませんけど、そういう根本的な問題はないんじゃない?
だってそういうのが起こるなら、欠陥 OS だから。
hirao
[E-Mail]
1999/10/02(土) 05:10:06
うまい言葉が見つからなかったもので分かりにくくなりましたが、
ようするにバッフアの問題があるのでは?
バッフア上のデータは、プロセス固有ですよね? それがグローバル
に他のプロセスで読めるようになるには、バッファの書出が終わるに
は、どれぐらいのタイミングがかかるか分からないのでは?
と思うのですが…?
あくまでperl&OSがflockで保証しているのは、そのflockされて
いるファイルであって、それ以上はperlやOSの責任ではないですの
で… 他のファイルにも効果が及ぶことを無闇に期待するのはプロ
グラマーのロジックとしては問題で、バグの元だと思います。
バッファのデータがディスクやそのグローバルなキャッシュに移さ
れるまでのタイミングが、ロック用のファイルのロックが解かれるよ
り速いことはどうプログラム上あるいはperl&OS上で保証されている
のでしょうか?(それをプログラム上で保証するのがプログラムな訳
です。flockされたファイルだけについてはperlやOSが保証してくれ
るわけで… とりあえず不完全ですが、ロック用のファイルのclose
の前にsleepで数秒ほど入れてみては?)
ちなみに、ファイルの排他制御についてはネットニュースの
fj.net.www.authoringで話題になっていたもので見に来ました(^^
>> とりあえず推測としては、ファイルの読込って、ディスクの物を読み
>> 込むのか、メモリーのキャッシュの物を読み込むのかその辺がどうなっ
>> ているのでしょうね…?
>推測に過ぎませんけど、そういう根本的な問題はないんじゃない?
>だってそういうのが起こるなら、欠陥 OS だから。
うまい言葉が見つからなかったもので分かりにくくなりましたが、
ようするにバッフアの問題があるのでは?
バッフア上のデータは、プロセス固有ですよね? それがグローバル
に他のプロセスで読めるようになるには、バッファの書出が終わるに
は、どれぐらいのタイミングがかかるか分からないのでは?
と思うのですが…?
あくまでperl&OSがflockで保証しているのは、そのflockされて
いるファイルであって、それ以上はperlやOSの責任ではないですの
で… 他のファイルにも効果が及ぶことを無闇に期待するのはプロ
グラマーのロジックとしては問題で、バグの元だと思います。
バッファのデータがディスクやそのグローバルなキャッシュに移さ
れるまでのタイミングが、ロック用のファイルのロックが解かれるよ
り速いことはどうプログラム上あるいはperl&OS上で保証されている
のでしょうか?(それをプログラム上で保証するのがプログラムな訳
です。flockされたファイルだけについてはperlやOSが保証してくれ
るわけで… とりあえず不完全ですが、ロック用のファイルのclose
の前にsleepで数秒ほど入れてみては?)
ちなみに、ファイルの排他制御についてはネットニュースの
fj.net.www.authoringで話題になっていたもので見に来ました(^^
J.Naka
1999/10/02(土) 12:29:29
上のメモリーのキャッシュってはプロセス側のキャッシュ領域=バッファて事とすると、
OS管轄外のプログラマ管理のバッファの操作はプログラマ一任(あたりまえ(^^;)。
バッファ操作の最後が書き出し或いは複数回の読み込みがあるなら、バッファ操作開始時点で、OS側にターゲットファイルの排他を要請し、ロック成功が返ってからバッファへの読み書きを行う。
ロックってのは、物理動作だから、それに同期しない&出来ないプログラムは駄目っす。
また、物理ロックを完全に処理できないOS(つまりユーザープログラム下位層)は、さらに駄目。って、そんなOSないでしょう。
> とりあえず推測としては、ファイルの読込って、ディスクの物を読み
> 込むのか、メモリーのキャッシュの物を読み込むのかその辺がどうなっ
> ているのでしょうね…?
上のメモリーのキャッシュってはプロセス側のキャッシュ領域=バッファて事とすると、
OS管轄外のプログラマ管理のバッファの操作はプログラマ一任(あたりまえ(^^;)。
バッファ操作の最後が書き出し或いは複数回の読み込みがあるなら、バッファ操作開始時点で、OS側にターゲットファイルの排他を要請し、ロック成功が返ってからバッファへの読み書きを行う。
ロックってのは、物理動作だから、それに同期しない&出来ないプログラムは駄目っす。
また、物理ロックを完全に処理できないOS(つまりユーザープログラム下位層)は、さらに駄目。って、そんなOSないでしょう。
J.Naka
1999/10/02(土) 18:15:33
Perl等のインタプリタ環境におけるファイル排他に関して前々から少し気になってる事あるのです(解答もらった事もありますが)。
Perlで、flock実行中にOSのマルチタスクによりプロセスの切り替えが発生し他のプロセスが同一のflockを実行しようとした場合、これはPerl上の命令flock自身が正確に排他されるのでしょうか?
インタプリタPerlの下位フェーズ(VXDとかBIOSとかコンピューターシステム内の物理レベルよりという意味)では、flockのコード自体はマルチタスク的に完全に排他されるでしょうが、インタプリタ自体はOSからは自由にマルチタスクされるような気がするので、システム上位フェースのPerl部分で排他ロジックが破錠する隙が存在するような気がするのですが。
#かなり、ずれているような気もします(^^;
Perl等のインタプリタ環境におけるファイル排他に関して前々から少し気になってる事あるのです(解答もらった事もありますが)。
Perlで、flock実行中にOSのマルチタスクによりプロセスの切り替えが発生し他のプロセスが同一のflockを実行しようとした場合、これはPerl上の命令flock自身が正確に排他されるのでしょうか?
インタプリタPerlの下位フェーズ(VXDとかBIOSとかコンピューターシステム内の物理レベルよりという意味)では、flockのコード自体はマルチタスク的に完全に排他されるでしょうが、インタプリタ自体はOSからは自由にマルチタスクされるような気がするので、システム上位フェースのPerl部分で排他ロジックが破錠する隙が存在するような気がするのですが。
#かなり、ずれているような気もします(^^;
hirao
[E-Mail]
1999/10/02(土) 22:47:01
それがflockされているファイルでしたら、上記の通りだと思いま
すが、flockされていないログ用のファイルについてもそれが期待で
きるかと言うことが知りたいんですよ…
つまり一番上のプログラムのclose(LOG);の次の所が実行されると
きには、その瞬間に他のプロセスでもclose(LOG);されたファイル
がcloseされていて正常に読み込めるのかと言うことが知りたいわけ
です。言い方を変えると、closeしたファイルが他のプロセスでも読
み込めるようになったところでperlのcloseから戻ってくると言うようなこ
とが規格とかOSのマニュアルで保証されているのか?と言うこと
が知りたいのです。もしそのファイルがOSレベルで本当にcloseさ
れる瞬間がclose(LOCK);より後になってしまった場合問題が発生す
る可能性があるのではないかなっと… マルチタスクなOS&プログ
ラムだとその辺の順序が予測しにくいですので…
その辺のことをプログラムする側が知らないのであれば、そこの
順序がずれていてもいいようにプログラムするのが、プログラマーと
してのロジックでしょうと僕は未熟者ながら言わせていただきました。
そう言うわけで僕が知りたいのはその辺の順序がどうなっているの
かという点で、それが証明されましたら、僕の危惧は無視していいこ
とになります。
>物理ロックを完全に処理できないOS(つまりユーザープログラム
>下位層)は、さらに駄目。って、そんなOSないでしょう。
それがflockされているファイルでしたら、上記の通りだと思いま
すが、flockされていないログ用のファイルについてもそれが期待で
きるかと言うことが知りたいんですよ…
つまり一番上のプログラムのclose(LOG);の次の所が実行されると
きには、その瞬間に他のプロセスでもclose(LOG);されたファイル
がcloseされていて正常に読み込めるのかと言うことが知りたいわけ
です。言い方を変えると、closeしたファイルが他のプロセスでも読
み込めるようになったところでperlのcloseから戻ってくると言うようなこ
とが規格とかOSのマニュアルで保証されているのか?と言うこと
が知りたいのです。もしそのファイルがOSレベルで本当にcloseさ
れる瞬間がclose(LOCK);より後になってしまった場合問題が発生す
る可能性があるのではないかなっと… マルチタスクなOS&プログ
ラムだとその辺の順序が予測しにくいですので…
その辺のことをプログラムする側が知らないのであれば、そこの
順序がずれていてもいいようにプログラムするのが、プログラマーと
してのロジックでしょうと僕は未熟者ながら言わせていただきました。
そう言うわけで僕が知りたいのはその辺の順序がどうなっているの
かという点で、それが証明されましたら、僕の危惧は無視していいこ
とになります。
とほほ
1999/10/02(土) 23:58:42
OSのバグでも無い限り、正確に排除されます。
インタプリタだろうが、アセンブラだろうが、結局はOSの排他制御機構
を呼び出すので同じことです。排他制御はプロセス同士が行うのではな
く、OSが行います。
バッファには2つあります。ひとつはプロセス固有の書き込みバッファ、
もうひとつはOS内部の書き込みバッファ(ディスクキャッシュ)。
printした時点ではデータはプロセス固有の書き込みバッファにたまり
ます。close()した時点でバッファがフラッシュされ、OSのディスクキ
ャッシュにたまり、flock()によるロックが解除されます。
Perl5.003_94よりも古いPerlでは、close()の前にflock()のロック
解除を行うと、データがバッファに溜まったまま別のプロセスが読み
書き可能になるので、まずいそうです。最近のバージョンでは、flock()
した時点で必ずバッファフラッシュが行われるそうです。
プロセス固有バッファから、ディスクキャッシュにデータが移動した時
点で、flock()のブロックから起き上がったプロセスがファイルを読み
込むと、ディスクキャッシュから読み込みます。
ディスクキャッシュは適当なタイミングでハードディスクに保存されま
すが、保存される前にシステムがストールしたりすると、書き込んだは
ずのデータが書き込まれていなかったりします。
> Perl上の命令flock自身が正確に排他されるのでしょうか?
OSのバグでも無い限り、正確に排除されます。
> インタプリタ自体はOSからは自由に・・・
インタプリタだろうが、アセンブラだろうが、結局はOSの排他制御機構
を呼び出すので同じことです。排他制御はプロセス同士が行うのではな
く、OSが行います。
> ディスクの物を読み込むのか、メモリーのキャッシュの物を・・・
バッファには2つあります。ひとつはプロセス固有の書き込みバッファ、
もうひとつはOS内部の書き込みバッファ(ディスクキャッシュ)。
printした時点ではデータはプロセス固有の書き込みバッファにたまり
ます。close()した時点でバッファがフラッシュされ、OSのディスクキ
ャッシュにたまり、flock()によるロックが解除されます。
Perl5.003_94よりも古いPerlでは、close()の前にflock()のロック
解除を行うと、データがバッファに溜まったまま別のプロセスが読み
書き可能になるので、まずいそうです。最近のバージョンでは、flock()
した時点で必ずバッファフラッシュが行われるそうです。
プロセス固有バッファから、ディスクキャッシュにデータが移動した時
点で、flock()のブロックから起き上がったプロセスがファイルを読み
込むと、ディスクキャッシュから読み込みます。
ディスクキャッシュは適当なタイミングでハードディスクに保存されま
すが、保存される前にシステムがストールしたりすると、書き込んだは
ずのデータが書き込まれていなかったりします。
J.Naka
1999/10/03(日) 01:40:41
とほほさん、詳しい説明有り難う御座います。
つまり、perlの排他処理(flock)は、以前のバージョンでは不完全な部分はあったけれど、今はユーザープロセスからOS処理まで切れ目のない連続した一個の排他処理となっているということですね。
Re:hiraoさん
そうなんです、同期をとるため連続実行していなければならいな一連のコード群がマルチタスクによって 細切れ & 順不同 & 多重実行 される可能性あるのではないかと心配だったのです。
-----------------------------
スレッド先頭に戻りますが、
Re:山本伸也さん
perlのflockが完全であるならば、このような失敗は起きえないはずが起きると。
これは、実はflockの排他処理は、
1.ハンドルに対して行われる
2.だから別ハンドルはオープンできてしまう
3.或いは、ハンドルはプロセスローカルである
とか?
実は、OS側で、open & close と flock とは連係していなく、独立して動作する。つまり非同期だった。
とか?
とほほさん、詳しい説明有り難う御座います。
つまり、perlの排他処理(flock)は、以前のバージョンでは不完全な部分はあったけれど、今はユーザープロセスからOS処理まで切れ目のない連続した一個の排他処理となっているということですね。
Re:hiraoさん
>マルチタスクなOS&プログラムだとその辺の順序が予測しにくいですので…
そうなんです、同期をとるため連続実行していなければならいな一連のコード群がマルチタスクによって 細切れ & 順不同 & 多重実行 される可能性あるのではないかと心配だったのです。
-----------------------------
スレッド先頭に戻りますが、
Re:山本伸也さん
>私が最初の発言で示した方法がなぜ失敗するのか、どうしても理解できないのです。
perlのflockが完全であるならば、このような失敗は起きえないはずが起きると。
これは、実はflockの排他処理は、
1.ハンドルに対して行われる
2.だから別ハンドルはオープンできてしまう
3.或いは、ハンドルはプロセスローカルである
とか?
実は、OS側で、open & close と flock とは連係していなく、独立して動作する。つまり非同期だった。
とか?
通りすがり
1999/10/03(日) 02:22:56
flock(LOCK, 2) || die "あんたの負け";
OS疑うより自分のプログラム疑うが定石。
flock(LOCK, 2) || die "あんたの負け";
OS疑うより自分のプログラム疑うが定石。
hirao
[E-Mail]
1999/10/03(日) 03:40:50
flockでブロックされているファイル同士だと、それで問題ないと思いますが、このスレッドで話されているプログラムには、排他制御用のファイルと、その処理の内側にあるflockされていないログ記録用ファイルの2種類があるのです。
ログ記録用のファイルのcloseの直後に排他制御用のファイルをcloseしてflockを解いているのですが、もし、ログ記録用のファイルのcloseから戻ってきた時点でもそのファイルが他のプロセスで反映されてないと言うようなことがあったとして(もちろんファイルの更新が他のプロセスで反映されてからcloseから戻ってくると言うことが決まっているのであれば、僕の心配は必要ないことになりますが…)、排他制御用のファイルのcloseが行われ(このファイルは更新されていないとすると、flockのフラグを解くだけで一瞬で終わる)、flockのブロックで待っていた次のプロセスが動きだし、僕の心配ではOSレベルでclose中の他のプロセスではまだ読めないかもしれない直接にはflockされていないログ記録用のファイルを読み込むことになる。そのタイミングはファイルの更新中かもしれなくて読み込むには一番やばいタイミングになるかもしれない、と言うことなんですが…
perlの処理とOSレベルのファイル操作がすべて同一プロセスで順序だって行われているのであれば、僕の考えている心配はいらないのですが、perlの処理と、OSレベルのファイル操作が別のプロセスで分離されて行われてた場合は処理によっては後回しになる可能性はないかと言うことでして、複雑なOSであればその辺の処理の順序がばらばらになる可能性はないのかなって事です。もちろんflockされているファイルについてはその辺でつじつまが合わなくなることはないようにしていないとOSのバグになりますが、flockされていないファイルについては同期させる義務はOSにはないのではないかと(もちろんプロセス内ではそれらのつじつまが合わないといけないですが、他のプロセスまでflockなどの排他処理が直接関わるところ以外でも同期させる必要があるのか…)その点が謎な訳ですね…
>プロセス固有バッファから、ディスクキャッシュにデータが移動した時
>点で、flock()のブロックから起き上がったプロセスがファイルを読み
>込むと、ディスクキャッシュから読み込みます。
flockでブロックされているファイル同士だと、それで問題ないと思いますが、このスレッドで話されているプログラムには、排他制御用のファイルと、その処理の内側にあるflockされていないログ記録用ファイルの2種類があるのです。
ログ記録用のファイルのcloseの直後に排他制御用のファイルをcloseしてflockを解いているのですが、もし、ログ記録用のファイルのcloseから戻ってきた時点でもそのファイルが他のプロセスで反映されてないと言うようなことがあったとして(もちろんファイルの更新が他のプロセスで反映されてからcloseから戻ってくると言うことが決まっているのであれば、僕の心配は必要ないことになりますが…)、排他制御用のファイルのcloseが行われ(このファイルは更新されていないとすると、flockのフラグを解くだけで一瞬で終わる)、flockのブロックで待っていた次のプロセスが動きだし、僕の心配ではOSレベルでclose中の他のプロセスではまだ読めないかもしれない直接にはflockされていないログ記録用のファイルを読み込むことになる。そのタイミングはファイルの更新中かもしれなくて読み込むには一番やばいタイミングになるかもしれない、と言うことなんですが…
perlの処理とOSレベルのファイル操作がすべて同一プロセスで順序だって行われているのであれば、僕の考えている心配はいらないのですが、perlの処理と、OSレベルのファイル操作が別のプロセスで分離されて行われてた場合は処理によっては後回しになる可能性はないかと言うことでして、複雑なOSであればその辺の処理の順序がばらばらになる可能性はないのかなって事です。もちろんflockされているファイルについてはその辺でつじつまが合わなくなることはないようにしていないとOSのバグになりますが、flockされていないファイルについては同期させる義務はOSにはないのではないかと(もちろんプロセス内ではそれらのつじつまが合わないといけないですが、他のプロセスまでflockなどの排他処理が直接関わるところ以外でも同期させる必要があるのか…)その点が謎な訳ですね…
B-Cus
1999/10/03(日) 07:26:47
close(LOCK) が実行される前に close(LOG) が実行されると。
ということは、flock解除の前にシステムコール close は
終了してるわけですよね。
「システムコール close が終了してもバッファに残っているのではないか」
と危惧するということは、OS を疑っているわけでしょ?
だって close した後、実際にディスクに書き込むのは
一般プログラムではなく OS の仕事なんだから、
もしバッファに残っているとしたら、それはプロセスの
バッファではなく、OSのバッファでしょう。
で、それを疑うって事は
open(OUT,">file"); print OUT "hoge"; close(OUT);
open(IN,"file"); $buf=<IN>; close(IN);
というコードで、$buf には "hoge" が入らないのでは
ないか、と疑うことと等価ですよね。
なぜなら、この場合 1つのプロセスで行うか2つのプロセスで
行うか、ということは関係なくて、
「あるファイルに書き込んで、システムコール close が終了した後に、
同じファイルを読み込むと、OS の古いデータを返すのではないか」
ということなんだから。
で、そんな挙動をする OS は存在しないでしょうから、
杞憂だろう、と言っているんです。
close(LOCK) が実行される前に close(LOG) が実行されると。
ということは、flock解除の前にシステムコール close は
終了してるわけですよね。
「システムコール close が終了してもバッファに残っているのではないか」
と危惧するということは、OS を疑っているわけでしょ?
だって close した後、実際にディスクに書き込むのは
一般プログラムではなく OS の仕事なんだから、
もしバッファに残っているとしたら、それはプロセスの
バッファではなく、OSのバッファでしょう。
で、それを疑うって事は
open(OUT,">file"); print OUT "hoge"; close(OUT);
open(IN,"file"); $buf=<IN>; close(IN);
というコードで、$buf には "hoge" が入らないのでは
ないか、と疑うことと等価ですよね。
なぜなら、この場合 1つのプロセスで行うか2つのプロセスで
行うか、ということは関係なくて、
「あるファイルに書き込んで、システムコール close が終了した後に、
同じファイルを読み込むと、OS の古いデータを返すのではないか」
ということなんだから。
で、そんな挙動をする OS は存在しないでしょうから、
杞憂だろう、と言っているんです。
B-Cus
1999/10/03(日) 07:36:13
あと、
なぜ「同じプロセス」「別のプロセス」という区別をしようと
するのかわかりません。OSにとっては、どれもただのプロセスでしょう。
あと、
> 他のプロセスではまだ読めないかもしれない
なぜ「同じプロセス」「別のプロセス」という区別をしようと
するのかわかりません。OSにとっては、どれもただのプロセスでしょう。
J.Naka
1999/10/03(日) 20:52:51
あぁ、flockしていないファイルを複数プロセス(単プロセス含む)から多重アクセスされる場合のファイル保護は誰がするか?
ということですね。
それは、誰もしないと思います。OS側に排他制御を要請してないので、OSはアプリからのAP発行を物理デバイスのバッティングが起きない限り、発行順に処理するのでは?。アプリ側にはてみれば、他に同一アクセスするプロセスがあることを知るすべもなく、自分勝手にやるしかないです。当然、1つのファイルへ同時アクセスが起きれば、そのファイルは壊れるでしょう。
え~と、マルチタスクOSの内部動作を考察して、こんな場合は危ない&これは起きえるとか思考シュミレーションするのは楽しく有意義ですが、実際のOSは長い歴史を経ており、そこいらは古典的テクニックの枯れた技術に分類されるのではないでしょうか。
問題は、そんなOSの上で動くアプリ(言語等)が、たまにミスする事だと思います。
この複雑OSってのは、TSSからみたリアルタイムマルチタスクOSあたりを指すのだと思います。排他制御が要請されれば、OSはそれらの処理がバッティングしないように、システム実行効率優先モードから、排他制御実現モードにスイッチするのだと思います。
そうでなければ、各プロセスの育成順&プライオリティにより、OSがてんでばらばらに処理(しているよにも見える)することになるのだと思います。
同時アクセスされる可能性のあるファイルをOSに排他処理まかせないなら、アプリ側がそれをやらないと同時アクセスされるファイルは壊れます。
---------------------------
えーと、あのさ、
・ファイルは同時アクセスされると壊れる。
・壊れて良いファイルは存在しない。
ならば、アプリ側に明示的に排他制御をかけるのではなく、それらはOSが行う、アプリ側から見るファイルI/O操作から隠蔽された裏方作業と位置づけるのが妥当のような気がします。
同一ファイルへの同時アクセスなんかOSには簡単に解かって当然&オーバーヘッド極小の処理のように思います。
> flockでブロックされているファイル同士だと、それで問題ないと思いますが、このスレッドで話されているプログラムには、排他制御用のファイルと、その処理の内側にあるflockされていないログ記録用ファイルの2種類があるのです。
あぁ、flockしていないファイルを複数プロセス(単プロセス含む)から多重アクセスされる場合のファイル保護は誰がするか?
ということですね。
それは、誰もしないと思います。OS側に排他制御を要請してないので、OSはアプリからのAP発行を物理デバイスのバッティングが起きない限り、発行順に処理するのでは?。アプリ側にはてみれば、他に同一アクセスするプロセスがあることを知るすべもなく、自分勝手にやるしかないです。当然、1つのファイルへ同時アクセスが起きれば、そのファイルは壊れるでしょう。
え~と、マルチタスクOSの内部動作を考察して、こんな場合は危ない&これは起きえるとか思考シュミレーションするのは楽しく有意義ですが、実際のOSは長い歴史を経ており、そこいらは古典的テクニックの枯れた技術に分類されるのではないでしょうか。
問題は、そんなOSの上で動くアプリ(言語等)が、たまにミスする事だと思います。
>複雑なOSであればその辺の処理の順序がばらばらになる可能性はないのかなって事です。
この複雑OSってのは、TSSからみたリアルタイムマルチタスクOSあたりを指すのだと思います。排他制御が要請されれば、OSはそれらの処理がバッティングしないように、システム実行効率優先モードから、排他制御実現モードにスイッチするのだと思います。
そうでなければ、各プロセスの育成順&プライオリティにより、OSがてんでばらばらに処理(しているよにも見える)することになるのだと思います。
>他のプロセスまでflockなどの排他処理が直接関わるところ以外でも同期させる必要があるのか…)その点が謎な訳ですね…
同時アクセスされる可能性のあるファイルをOSに排他処理まかせないなら、アプリ側がそれをやらないと同時アクセスされるファイルは壊れます。
---------------------------
えーと、あのさ、
・ファイルは同時アクセスされると壊れる。
・壊れて良いファイルは存在しない。
ならば、アプリ側に明示的に排他制御をかけるのではなく、それらはOSが行う、アプリ側から見るファイルI/O操作から隠蔽された裏方作業と位置づけるのが妥当のような気がします。
同一ファイルへの同時アクセスなんかOSには簡単に解かって当然&オーバーヘッド極小の処理のように思います。
J.Naka
1999/10/03(日) 20:55:06
▲訂正
最終段落の
ならば、アプリ側で明示的に排他制御を
▲訂正
最終段落の
>ならば、アプリ側に明示的に排他制御を
ならば、アプリ側で明示的に排他制御を
とほほ
1999/10/04(月) 00:53:32
以前のバージョンでも『排他処理』は完璧です。flock(ロック解除)す
る前に自分でバッファをフラッシュするか、ロック解除をclose()にま
かせてしまえばいいだけのことです。
flock()によるロックが完璧でも、ファイルは壊れます。
OSやPerlのバグでも無い限り、そのようなことは無いので安心してください。
一番最初の山本さんのプログラムの場合、ロック処理(排他制御)に関
しては完璧です。ロックの不完全さが原因で壊れることはありません。
ただ、ファイルのロックとは別の理由で壊れます。おそらく、シングル
プロセスのOSで動かしても壊れますよね。これ。
> perlの排他処理(flock)は、以前のバージョンでは不完全な・・・
以前のバージョンでも『排他処理』は完璧です。flock(ロック解除)す
る前に自分でバッファをフラッシュするか、ロック解除をclose()にま
かせてしまえばいいだけのことです。
> Perlのflockが完全であるならば、このような失敗は起きえないはず
> が起きると。
flock()によるロックが完璧でも、ファイルは壊れます。
> closeから戻ってきた時点でもそのファイルが他のプロセスで反映さ
> れてないと言うようなことがあったとして
OSやPerlのバグでも無い限り、そのようなことは無いので安心してください。
一番最初の山本さんのプログラムの場合、ロック処理(排他制御)に関
しては完璧です。ロックの不完全さが原因で壊れることはありません。
ただ、ファイルのロックとは別の理由で壊れます。おそらく、シングル
プロセスのOSで動かしても壊れますよね。これ。
hirao
[E-Mail]
1999/10/04(月) 03:19:00
closeのプロセス間での同期と言うことでは、僕の考えたような心
配はないわけですね… ありがとうございました。今後は余分なこと
は考えず、closeに関しては(ほかのファイル操作でも?)そう言う
考え方でプログラムしていくことにします。
なにぶんまだ未熟者ですので、OSレベルのことは理解していないも
ので、分からないことはできるだけいろいろ想定して対処していくよ
うにしているものですから、そう言う余計なことまで考えてしまいま
した。
open(LOG,"> と書込モードでopenはまずいですよね…
書込モードのopenだけでフラッシュされてしまうのですよね?
だとするとcloseされるまでに何らかの理由でプロセスが消されれば、
そのファイルはゼロにされてしまいますよね…
やはりこの場合でも+<でopenするようにしないとまずいわけですね。
この方法でopenしたファイルはcloseされるかバッファがいっぱいに
なるなどするまでフラッシュされないわけですから、この場合の方が
安全? closeはOSレベルですから中断する可能性は低いですし、賢
いディスクアクセスなら途中で止まっても壊れないようにしているか
もしれないですし…(はずしていましたらすいませんです(^^;; )
truncateもcloseの直前でtruncate(FILEHANDLE,tell)みたいにす
るのがよいのでしょうか? それから今見たマニュアルではseek(,0,2)で最後に追加の場合はflock(,2)の後にseekが要ると言うこと
も書いてましたね(^^;; たしかに考えてみればopenからflock
までの間でアクセスされるとずれてしまうんでしょうね…? と言う
ことでファイルアクセスはperl初心者には超難解なところがありま
すね…(^^;; (Winなんかだとopenの所で排他制御ができるも
ので、ここまで複雑ではないもので…)
closeのプロセス間での同期と言うことでは、僕の考えたような心
配はないわけですね… ありがとうございました。今後は余分なこと
は考えず、closeに関しては(ほかのファイル操作でも?)そう言う
考え方でプログラムしていくことにします。
なにぶんまだ未熟者ですので、OSレベルのことは理解していないも
ので、分からないことはできるだけいろいろ想定して対処していくよ
うにしているものですから、そう言う余計なことまで考えてしまいま
した。
>一番最初の山本さんのプログラムの場合、ロック処理(排他制御)に関
>しては完璧です。ロックの不完全さが原因で壊れることはありません。
>ただ、ファイルのロックとは別の理由で壊れます。おそらく、シングル
>プロセスのOSで動かしても壊れますよね。これ。
open(LOG,"> と書込モードでopenはまずいですよね…
書込モードのopenだけでフラッシュされてしまうのですよね?
だとするとcloseされるまでに何らかの理由でプロセスが消されれば、
そのファイルはゼロにされてしまいますよね…
やはりこの場合でも+<でopenするようにしないとまずいわけですね。
この方法でopenしたファイルはcloseされるかバッファがいっぱいに
なるなどするまでフラッシュされないわけですから、この場合の方が
安全? closeはOSレベルですから中断する可能性は低いですし、賢
いディスクアクセスなら途中で止まっても壊れないようにしているか
もしれないですし…(はずしていましたらすいませんです(^^;; )
truncateもcloseの直前でtruncate(FILEHANDLE,tell)みたいにす
るのがよいのでしょうか? それから今見たマニュアルではseek(,0,2)で最後に追加の場合はflock(,2)の後にseekが要ると言うこと
も書いてましたね(^^;; たしかに考えてみればopenからflock
までの間でアクセスされるとずれてしまうんでしょうね…? と言う
ことでファイルアクセスはperl初心者には超難解なところがありま
すね…(^^;; (Winなんかだとopenの所で排他制御ができるも
ので、ここまで複雑ではないもので…)
山本晋也
1999/10/04(月) 13:15:58
難しい議論が出てますが、とほほさんの
で安心しました。
で、ここで聞いたことを元に自分でもいろいろ調べて、以下のように書き直したのですが、
これで信頼性はかなり上がったと思います。
一応、これで行こうと思い、勝手ながら解決にさせていただきます。
みなさま、ありがとうございました。
# 排他制御開始
open(LOCK, "$file");
flock(LOCK, 2);
# ログの読み込み
open(LOG, "$logfile");
@log = <LOG>;
close(LOG);
# 処理
・・・・・・
# ログの書き込み
open(LOG, "+<$logfile");
seek(LOG, 0, 0)
print LOG @log;
truncate(LOG, tell);
close(LOG);
# 排他制御終了
close(LOCK);
難しい議論が出てますが、とほほさんの
>一番最初の山本さんのプログラムの場合、ロック処理(排他制御)に関
>しては完璧です。
で安心しました。
で、ここで聞いたことを元に自分でもいろいろ調べて、以下のように書き直したのですが、
これで信頼性はかなり上がったと思います。
一応、これで行こうと思い、勝手ながら解決にさせていただきます。
みなさま、ありがとうございました。
# 排他制御開始
open(LOCK, "$file");
flock(LOCK, 2);
# ログの読み込み
open(LOG, "$logfile");
@log = <LOG>;
close(LOG);
# 処理
・・・・・・
# ログの書き込み
open(LOG, "+<$logfile");
seek(LOG, 0, 0)
print LOG @log;
truncate(LOG, tell);
close(LOG);
# 排他制御終了
close(LOCK);
せがわ ぴん
1999/10/04(月) 19:22:11
カントクゥー
解決忘れてますよ!!
カントクゥー
解決忘れてますよ!!
山本晋也
1999/10/05(火) 13:17:00
[[解決]]
失礼しました。忘れてました。
[[解決]]
失礼しました。忘れてました。
匿名希望
1999/12/04(土) 14:25:41
ロックについて検索したら、
このスレッドが見つかりました。
ちょっと気になったので質問させて欲しいのですが、
open(LOG, "+<$logfile");
seek(LOG, 0, 0)
print LOG @log;
truncate(LOG, tell);
close(LOG);
って意味がないと思うのですが。
open(LOG, ">$logfile");
print LOG @log;
close(LOG);
でかまわないのではないでしょうか。
ここではファイルサイズがゼロになるタイミング(?)なんて
問題にならないわけですよね。(すでにロックされているから。)
また、open(IN, "+<FILE");とopen(IN, "+>FILE");
に差はあるのでしょうか。
よろしくお願いします。
ロックについて検索したら、
このスレッドが見つかりました。
ちょっと気になったので質問させて欲しいのですが、
open(LOG, "+<$logfile");
seek(LOG, 0, 0)
print LOG @log;
truncate(LOG, tell);
close(LOG);
って意味がないと思うのですが。
open(LOG, ">$logfile");
print LOG @log;
close(LOG);
でかまわないのではないでしょうか。
ここではファイルサイズがゼロになるタイミング(?)なんて
問題にならないわけですよね。(すでにロックされているから。)
また、open(IN, "+<FILE");とopen(IN, "+>FILE");
に差はあるのでしょうか。
よろしくお願いします。