プログラム終了時のファイル削除の保証(C / C ++)
-
19-08-2019 - |
質問
Win32の CreateFile
には<= >しかし、私はLinuxを使用しています。
プログラムの終了時に常に削除される一時ファイルを開きたい。プログラムがクラッシュした場合、これを保証することは実用的ではないかもしれないことを理解できましたが、他の場合には動作させたいと思います。
RAIIについて知っています。信号について知っています。 FILE_FLAG_DELETE_ON_CLOSE
について知っています。ファイルを開いてすぐに削除でき、ファイル記述子が閉じられる(クラッシュを処理する)までファイルにアクセスできることを知っています。これらはどれも完全で簡単な解決策のようには見えません。
- RAII:行ったこと、行ったこと:デストラクタがファイルを削除するオブジェクトがありますが、プログラムがシグナルで終了した場合、デストラクタは呼び出されません。
- signals:シグナルハンドラーの登録を困難にする低レベルのライブラリを作成しています。たとえば、アプリケーションが信号自体を使用する場合はどうなりますか?つま先を踏みつけたくありません。対処するために
atexit(3)
を巧妙に使用することを検討するかもしれませんが、まだこの可能性について十分に考えていません。 -
sigaction(2)
:異常終了中に呼び出されないため(たとえば、シグナル経由で)、明らかに役に立たない。 - プリエンプティブ
unlink(2)
:これは、ファイルシステムでファイルを表示したままにする必要があることを除いて、かなり良いです(そうしないと、システムの監視/トラブルシューティングが難しくなります)。
ここで何をしますか?
詳細な説明
元の投稿の詳細を1つ省略しました。 <!> quot; file <!> quot;この場合、厳密には通常のファイルではなく、POSIXメッセージキューです。 mq_open()
で作成します。 mq_close()
またはclose()
で閉じることができます(前者は私のシステムでは後者のエイリアスです)。 mq_unlink()
を使用してシステムから削除できます。これらはすべて、通常のファイルに類似していますが、例外は、ファイルが存在するディレクトリを選択できないことです。これは、<!> quot; file <!> quot;が原因で、現在最も人気のある回答(/tmp
にファイルを配置する)を実行できなくなります。非常に限られた容量の仮想ファイルシステムでシステムによって作成されます。 (/dev/mqueue
の例に従って、仮想ファイルシステムをman mq_overview
にマウントしました)。
これは、名前を表示したままにする必要がある理由も説明します(即時リンク解除アプローチを実行不能にする)。<!> quot; file <!> quot; 2つ以上のプロセス間で共有する必要があります。
解決
プロセスの実行中に名前を表示したままにするという要件により、これを達成するのが難しくなります。その要件を再検討できますか?
そうでない場合、おそらく完璧な解決策はありません。 Kamil Kisielが提案するものと信号処理戦略を組み合わせることを検討します。シグナルハンドラをインストールする前に、インストールされているシグナルハンドラを追跡できます。デフォルトのハンドラがSIG_IGNの場合、通常、独自のハンドラをインストールすることはありません。 SIG_DFLの場合、それを覚えているでしょう。それが何か他のものである場合-ユーザー定義のシグナルハンドラ-あなたはそのポインタを覚えていて、独自のものをインストールします。ハンドラーが呼び出されたら、必要なことは何でもし、記憶されているハンドラーを呼び出して、ハンドラーをチェーンします。 atexit()ハンドラーもインストールします。また、これを行うことと、それを行う信号を文書化します。
信号処理は不完全な戦略であることに注意してください。 SIGKILLはキャッチできず、atexit()ハンドラーは呼び出されず、ファイルは残されます。
David Segondの提案-一時ファイル名デーモン-は興味深いものです。単純なプロセスの場合、それで十分です。一時ファイルを要求するプロセスがフォークし、その後子がファイルを所有する(そして終了する)ことを期待する場合、デーモンはそれを使用する最後のプロセスがいつ死んだかを検出する問題を抱えています-開いているプロセスを自動的に認識しないためです
他のヒント
一時ファイルを作成している場合は、/tmp
またはそのサブディレクトリに作成します。次に、atexit(3)
または同様の方法で行ったときに、削除するために最善の努力をします。プログラムのクラッシュが原因で削除に失敗した場合でも、mkstemp(3)
などで選択された一意の名前を使用している限り、その後の実行やその他の条件で再度読み取るリスクはありません。
その時点では、<=>をクリーンに保つというシステムレベルの問題にすぎません。ほとんどのディストリビューションは、ブートまたはシャットダウン時にワイプするか、通常のcronジョブを実行して古いファイルを削除します。
誰かがすでにこれを提案したかもしれませんが、あなたのすべての要件を考えると、私はそれを見つけることができません、私が考えることができる最善の方法は、ファイル名を何らかの方法で親プロセス(たとえば、開始スクリプトプロセスが終了した後、失敗した場合はクリーンアップします。これはおそらくウォッチドッグとして知られていますが、より一般的なユースケースが追加され、何らかの理由でプロセスが失敗したときにプロセスを強制終了または再起動します。
親プロセスも死ぬ場合、あなたは運が悪いのですが、ほとんどのスクリプト環境はかなり堅牢であり、スクリプトが壊れていない限り死ぬことはめったにありません。 >
過去に、<!> quot;一時ファイルマネージャ<!> quot;を作成しました。一時ファイルを追跡しました。
マネージャーから一時ファイル名を要求し、この名前が登録されました。
一時ファイル名が不要になったら、マネージャーに通知すると、ファイル名が登録解除されます。
終了シグナルを受信すると、登録されているすべての一時ファイルが破壊されました。
一時的なファイル名は、衝突を避けるためにUUIDベースでした。
ファイルの作成後にプロセスフォークを使用し、子が閉じるのを待つと、親はファイルのリンクを解除して終了できます。
stackoverflowに参加しましたが、ここにいます:)
mqファイルを管理し、それらが蓄積しないようにすることが問題である場合、終了時にファイルの削除を保証する必要はありません。無駄なファイルを積み上げたいだけの場合は、ジャーナルを保持するだけで十分です。 mqが開かれた後にジャーナルファイルにエントリを追加し、閉じられたときに別のエントリを追加します。ライブラリが初期化されたら、ジャーナルの不整合をチェックし、不整合を修正するために必要なアクションを実行します。 mq_open/mq_close
が呼び出されているときにクラッシュすることが心配な場合は、それらの関数が呼び出される直前にジャーナルエントリを追加することもできます。
- ドットディレクトリの下に一時ファイル用の簿記ディレクトリを作成します。
- 一時ファイルを作成する場合、最初に、保存する一時ファイルへのパスまたはUUIDを含むブックキーピングディレクトリにブックキーピングファイルを作成します。
- その一時ファイルを作成します。
- 一時ファイルが削除されたら、簿記ファイルを削除します。
- プログラムが起動したら、一時ファイルへのパスを含むファイルがないか簿記ディレクトリをスキャンし、見つかった場合はそれらを削除して、簿記ファイルを削除します。
- (いずれかのステップが失敗した場合、ノイズを記録します。)
これをもっと簡単にする方法は見当たりません。これは、生産品質プログラムが通過しなければならない定型です。簡単に+500行。
名前を表示したままにする必要がある本当にですか?
ファイルのリンクをすぐに解除するオプションを選択したとします。次に:
-
プリエンプティブunlink(2):これは、ファイルシステムでファイルを表示したままにする必要があることを除いて、かなり良いです(そうしないと、システムの監視/トラブルシューティングが難しくなります)。
/proc/$pid/fd/
の下に表示されるため、削除されたファイルをデバッグできます。プロセスのPIDを知っている限り、開いているファイルを列挙するのは簡単です。 -
名前はプログラム間で共有されるため、通常の操作中は表示されたままにする必要があります。
ファイル記述子をUnixドメインソケット経由で渡すことにより、削除されたオープンファイルをプロセス間で共有できます。 異なるプロセス間でファイル記述子を渡すポータブルな方法をご覧ください。詳細については。