初めて、掲示板に質問致します。
開発環境は、Windows XP、VC 2005です。
fwriteしていた場合に、異常復帰する時(書き込んだ数以外)は、どのような理由で復帰
することが考えられるのでしょうか?
1秒に2回ほどfwriteする処理(シングルスレッド)を、3日間程連続稼動させていました。
fopen/fcloseは正常復帰(復帰値のエラーチェック有り)していたのですが、データが何
も無かったことを考えますと、fwriteが異常復帰(エラーチェック無し)した可能性が高
いです。
※fopen~fwrite~fcloseは、書き込むデータがある時にCALLされます。
もし、fwriteの異常復帰する原因に関して、ご存知の方がいましたら、お聞かせくださ
い。
情報が足りていませんでしたので、追記します。
1回に書き込むサイズは約8kbyteでして、1秒間当たりのfwriteの異常復帰しているであ
ろう発生頻度は、0.2%程度です。※3日間で3回。
処理であらわすと、以下の通りです。
fwrite(data_p, 8000, 1, fp);
fwrite が返却するのは実際に書き込んだレコード数
fwrite(buf, 8000, 1, fp); は「8000バイトのデータを1組」という意味になる
書き込み対象デバイス (ハードディスクやテープやコンソールやパイプや) に、
8000 バイト以上の空きがあって、実際に書き込めたら 1 が返却される
8000 バイト未満しか空きがないとか Quota 制約に引っかかったとか、
デバイスやファイルがロックされていて書き込めないとか
fp が「書き込み可能 fopen された FILE* 」を指していないとか、
何らかの理由で 8000 バイトが書き込めなかったら 0 となる
fwrite(buf, 1, 8000, fp); として fwrite の返却値をチェックすれば
もっと何かわかる可能性はあるだろうな
>tetrapodさん
御返事ありがとうございます。
ハードディスクにfwriteしているのですが、ユーザの制限によらず、8000バイト以上の
空きがある状態で発生しています。
また、書込み可能な fopen(file_name, ab);でオープンしております。
発生頻度も低く、同じ試験環境に今できませんので、fwriteの仕様が理解できたら対応
がしやすいと考えていました。
> ユーザの制限によらず、8000バイト以上の空きがある
「はず」と思い込んでいるが、たまたまその瞬間はそうでないとか
> 書込み可能な fopen(file_name, ab);でオープンしております。
fopen 自体は正しいのだが、その後メモリ破壊を起こしているとか
他のツール(特にウィルス対策ソフトの類)と共有違反しているとか
(今回はマルチスレッドぢゃ無いらしいから該当しないかもしれないが)
スレッドやプロセス間での排他処理が1箇所抜けているとか
fwrite が原因ではないに1票
>tetrapodさん
たびたびありがとうございます。
>他のツール(特にウィルス対策ソフトの類)と共有違反しているとか
可能性としまして有り得ます。ウィルス対策ソフトが、確か2つ程動作していました。
fopenしてファイル作成直後にウィルス対策ソフトが、そのファイルをチェックしている
期間中にfwriteしても異常復帰することが有り得るという事でしょうか?
>(今回はマルチスレッドぢゃ無いらしいから該当しないかもしれないが)
>スレッドやプロセス間での排他処理が1箇所抜けているとか
正確な理由が分からないので、宜しければ教えて頂きたいのですが、マルチスレッドや
マルチプロセスで起動していた場合に、1つの共有ファイルにアクセスしてデッドロック
が起こるから不味いのでしょうか?
>fwrite が原因ではないに1票
この可能性が一番高そうです。
ありがとうございます。
>そのファイルをチェックしている
>期間中にfwriteしても異常復帰することが有り得るという事でしょうか?
対象のファイルのセキュリティ属性などがチェック中に変更されたり、
ドライバなどによってアクセスが制限される場合、当然アクセスできずに
書き込みに失敗する可能性があります。
>1つの共有ファイルにアクセスしてデッドロック
>が起こるから不味いのでしょうか?
複数のプロセス間で同じファイルをオープンしても、
同期して待つという処理は自分で書かないといけません。
#つまり普通にオープンしただけではデッドロックなど起こりません。
もちろん同時に書き込みを行うわけなので、タイミングによっては
ファイルの中身が壊れます。このときファイル操作系関数の挙動が
どうなるかは、分からないので排他が必要ということだと思います。
#エラーになるかもしれないし、成功するかもしれない
>Haruさん
ありがとうございます。
>対象のファイルのセキュリティ属性などがチェック中に変更されたり、
>ドライバなどによってアクセスが制限される場合、当然アクセスできずに
>書き込みに失敗する可能性があります。
ドライバによって、急にアクセスが制限される場合があるのですね。
>もちろん同時に書き込みを行うわけなので、タイミングによっては
>ファイルの中身が壊れます。このときファイル操作系関数の挙動が
>どうなるかは、分からないので排他が必要ということだと思います。
>#エラーになるかもしれないし、成功するかもしれない
作成したアプリ側の処理では、シングルスレッドで、そのファイルを操作しています。
従いまして、他のアプリ(ウィルス対策ソフト)やOSレベルで対象としているファイルを
何かしらの操作/変更した場合は、保証が出来ない可能性があるということですね。
ありがとうございました。
fflushってご存知でしょうか
fwriteのようなストリーム入出力は遅延書き込みバッファを経由して
物理ファイルに書き込まれます
つまりクローズが成功していても、バッファ上にあるだけで
他の大量データ書き込みがある場合、すぐに物理ファイルに書き込まれません
クローズする前にfflushをつけて見てください
詳しくはMSDNで調べてね
fclose は、自身の処理の先頭で fflush してる。
「fflush を fclose の直前で」であれば、不要。
「fflush を fwrite の直後で」であれば、やってみてもいいかもしれない
けどバッファリングをしないわけだから性能は低下する。
fwrite 1箇所につき fflush を1つ追加するとなると書き換え量が多いし、
そこまでするくらいなら fopen 直後に setvbuf を強く推奨する。
まあいずれにせよメモリ破壊とかしてないのであれば、原因は f*** 関数ぢゃ無い
に1票をもう一度投じておく。
>woodさん
ありがとうございます。
プログラムを製作するのにも、色々と理解しないと完璧に近いものは製作できないです
ね。
遅延書き込みバッファという用語は知りませんでした。
>tetrapodさん
性能が低下するのは避けたいので、
>「fflush を fwrite の直後で」
も対応できないです。
f****関数では、無い気がしますので、もう少し範囲を広げて確認していきます。
tetrapodさん、Haruさん、woodさん、ありがとうございました。