終了する前に特定のタスクを実行する必要があるプログラムがあります。問題は、プログラムが例外(データベースに到達できないなど)でクラッシュすることがあることです。さて、異常終了を検出し、それが死ぬ前にいくつかのコードを実行する方法はありますか?
ありがとう。
コードをいただければ幸いです。
終了する前に特定のタスクを実行する必要があるプログラムがあります。問題は、プログラムが例外(データベースに到達できないなど)でクラッシュすることがあることです。さて、異常終了を検出し、それが死ぬ前にいくつかのコードを実行する方法はありますか?
ありがとう。
コードをいただければ幸いです。
1. Win32
Win32 APIには、次のように、 SetUnhandledExceptionFilter関数を介してこれを行う方法が含まれています。
LONG myFunc(LPEXCEPTION_POINTERS p)
{
printf("Exception!!!\n");
return EXCEPTION_EXECUTE_HANDLER;
}
int main()
{
SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)&myFunc);
// generate an exception !
int x = 0;
int y = 1/x;
return 0;
}
2. POSIX / Linux
私は通常、signal()関数を介してこれを行い、SIGSEGV信号を適切に処理します。SIGTERMシグナルとSIGINTを処理することもできますが、SIGKILLは処理できません(設計による)。strace()を使用してバックトレースを取得し、シグナルの原因を確認できます。
NT Internalsをフックしてエンドプロセスの試行から保護することについてのsysinternalsフォーラムスレッドがありますが、本当に必要なのは、ウォッチドッグまたはピアプロセス(合理的なアプローチ)または壊滅的なイベントを傍受する何らかの方法(かなり危険)です。
編集:これを困難にする理由はいくつかありますが、プロセスを強制終了する試みを傍受またはブロックすることは可能です。終了する前にクリーンアップしようとしているだけですが、誰かがすぐに強制終了できないプロセスをリリースするとすぐに、誰かがすぐに強制終了する方法などを要求します。とにかく、この道を進むには、上記のリンクされたスレッドを参照し、そこで見つけたいくつかのキーワードで詳細を検索してください。NtTerminateProcessなどをフックまたはフィルターします。ここでは、カーネルコード、デバイスドライバー、アンチウイルス、セキュリティ、マルウェア、ルートキットなどについて説明します。この分野で役立つ本には、Windows NT / 2000 Native API、文書化されていないWindows 2000 Secrets:A Programmer's Cookbook、Rootkits:Subverting theWindowsKernelがあります。、そしてもちろん、Windows®Internals:FifthEdition。このようなものはコーディングするのはそれほど難しいことではありませんが、うまくいくにはかなり扱いにくいものであり、予期しない副作用が発生する可能性があります。
おそらく、アプリケーションの回復および再起動機能が役立つ可能性がありますか?VistaおよびServer2008以降でサポートされています。
ApplicationRecoveryCallbackコールバック関数アプリケーションが未処理の例外に遭遇した場合、または応答しなくなった場合に、データとアプリケーションの状態情報を保存するために使用されるアプリケーション定義のコールバック関数。
SetUnhandledExceptionFilterの使用に関して、MSDN Socialディスカッションでは、これを確実に機能させるには、そのメソッドをメモリ内にパッチすることが、フィルターが確実に呼び出されるようにする唯一の方法であるとアドバイスしています。代わりに__try/__exceptでラップすることをお勧めします。とにかく、 「SetUnhandledExceptionFilter」とVC8の記事には、SetUnhandledExceptionFilterへの呼び出しのフィルタリングに関するサンプルコードと説明がいくつかあります。
また、AddVectoredExceptionHandlerのサンプルコードについては、TheAwesomeFactorで再検討されたWindowsSEHを参照してください。
それはあなたがあなたの「例外」をどうするかによります。それらを適切に処理してプログラムを終了する場合は、を使用して、終了時に呼び出される関数を登録できますatexit()
。
セグメンテーション違反のような実際の異常終了の場合は機能しません。
Windowsについてはわかりませんが、POSIX準拠のOSでは、さまざまなシグナルをキャッチしてそれに対して何かを行うシグナルハンドラーをインストールできます。もちろん、キャッチすることはできませSIGKILL
んSIGSTOP
。
SignalAPIはC89以降のANSICの一部であるため、おそらくWindowsがサポートしています。詳細についてsignal()
は、syscallを参照してください。
Windowsのみの場合は、SEH(SetUnhandledExceptionFilter)またはVEH(AddVectoredExceptionHandler、ただしXP / 2003以降のみ)を使用できます。
数年前、「事後デバッグ」に関する記事をddj.comに公開しました。
異常終了を検出するためのWindowsおよびUNIX/Linuxのソースが含まれています。ただし、私の経験では、SetUnhandledExceptionFilterを使用してインストールされたWindowsハンドラーが常に呼び出されるとは限りません。多くの場合、それは呼び出されますが、インストールされたハンドラーからのレポートが含まれていない顧客からかなりの数のログファイルを受け取ります。つまり、アクセス違反が原因でした。
申し訳ありませんが、Windowsプログラマーではありません。だけど、たぶん
_onexit()
プログラム終了時に呼び出される関数を登録します。
http://msdn.microsoft.com/en-us/library/aa298513%28VS.60%29.aspx
まず、これはかなり明白ですが、完全に堅牢なソリューションを実現することはできません。誰かがいつでも電源ケーブルを叩いてプロセスを終了することができます。したがって、妥協が必要であり、その妥協の詳細を注意深くレイアウトする必要があります。
より堅牢なソリューションの1つは、関連するコードをラッパープログラムに配置することです。ラッパープログラムは、「実際の」プログラムを呼び出し、そのプロセスが終了するのを待ってから、「実際の」プログラムが正常に完了したことを明確に通知しない限り、クリーンアップコードを実行します。これは、テストハーネスのように、テストプログラムがクラッシュしたり、中止したり、予期しない方法で停止したりする可能性がある場合によく見られます。
それでも、誰かがラッパー関数でTerminateProcessを実行した場合、それが心配する必要がある場合は、何が起こるかが難しくなります。必要に応じて、Windowsでサービスとして設定し、オペレーティングシステムの機能を使用して、システムが停止した場合に再起動することで、これを回避できます。(これにより、状況が少し変わります。誰かがサービスを停止する可能性があります。)この時点で、ファイルの作成などの永続的な方法で正常に完了したことを通知する必要があります。