71

C ++ Windowsアプリでは、長時間実行される子プロセスをいくつか起動します(現在、これを行うためにCreateProcess(...)を使用しています。

メインプロセスがクラッシュしたり閉じられたりした場合に、子プロセスを自動的に閉じたい。

これは「親」のクラッシュに対して機能する必要があるという要件があるため、オペレーティングシステムのAPI/機能を使用してこれを行う必要があると思います。すべての「子」プロセスがクリーンアップされるようにします。

どうすればよいですか?

4

7 に答える 7

84

Windows APIは、「ジョブオブジェクト」と呼ばれるオブジェクトをサポートしています。次のコードは、メインアプリケーションが終了したとき(ハンドルがクリーンアップされたとき)にすべてのプロセスをシャットダウンするように構成された「ジョブ」を作成します。このコードは1回だけ実行する必要があります。

HANDLE ghJob = CreateJobObject( NULL, NULL); // GLOBAL
if( ghJob == NULL)
{
    ::MessageBox( 0, "Could not create job object", "TEST", MB_OK);
}
else
{
    JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };

    // Configure all child processes associated with the job to terminate when the
    jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
    if( 0 == SetInformationJobObject( ghJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)))
    {
        ::MessageBox( 0, "Could not SetInformationJobObject", "TEST", MB_OK);
    }
}

次に、各子プロセスが作成されたら、次のコードを実行して各子プロセスを起動し、ジョブオブジェクトに追加します。

STARTUPINFO info={sizeof(info)};
PROCESS_INFORMATION processInfo;

// Launch child process - example is notepad.exe
if (::CreateProcess( NULL, "notepad.exe", NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo))
{
    ::MessageBox( 0, "CreateProcess succeeded.", "TEST", MB_OK);
    if(ghJob)
    {
        if(0 == AssignProcessToJobObject( ghJob, processInfo.hProcess))
        {
            ::MessageBox( 0, "Could not AssignProcessToObject", "TEST", MB_OK);
        }
    }

    // Can we free handles now? Not sure about this.
    //CloseHandle(processInfo.hProcess); 
    CloseHandle(processInfo.hThread);
}

VISTA注: VistaでAssignProcessToObject()でアクセス拒否の問題が発生した場合、VistaではAssignProcessToJobObjectが常に「アクセス拒否」を返すを参照してください。

于 2008-09-10T00:22:49.550 に答える
5

ややハックな解決策の1つは、親プロセスをデバッガーとして各子にアタッチすることです(DebugActiveProcessを使用)。デバッガーが終了すると、そのすべてのdebuggeeプロセスも終了します。

より良い解決策(子プロセスも作成したと仮定)は、子プロセスに親を監視させ、親がなくなった場合は終了させることです。

于 2008-09-10T00:28:13.920 に答える
3

Windowsジョブオブジェクトは、開始するのに適した場所のように思えます。ジョブオブジェクトの名前は、よく知られているか、子に渡される(またはハンドルを継承する)必要があります。子は、IPCの「ハートビート」の失敗、または親のプロセスハンドルのWFMO / WFSOのいずれかによって、親が死亡したときに通知する必要があります。その時点で、子プロセスはTermianteJobObjectでグループ全体を停止させることができます。

于 2008-09-10T06:24:54.967 に答える
1

別のウォッチドッグプロセスを実行し続けることができます。その唯一のタスクは、現在のプロセススペースを監視して、説明したような状況を見つけることです。クラッシュ後に元のアプリケーションを再起動したり、ユーザーにさまざまなオプションを提供したり、デバッグ情報を収集したりすることもできます。最初のウォッチドッグを監視するために2番目のウォッチドッグが必要ないように、十分にシンプルに保つようにしてください。

于 2008-09-10T00:25:40.853 に答える
-2

おそらく、開始したプロセスのリストを保持し、プログラムを終了するときにそれらを1つずつ強制終了する必要があります。C ++でこれを行う詳細はわかりませんが、難しいことではありません。難しいのは、アプリケーションがクラッシュした場合に子プロセスを確実にシャットダウンすることです。.Netには、未処理の例外が発生したときに呼び出される関数を追加する機能があります。C++が同じ機能を提供するかどうかはわかりません。

于 2008-09-10T00:19:50.493 に答える
-2

各プロセスをC++オブジェクトにカプセル化し、それらのリストをグローバルスコープに保持することができます。デストラクタは、各プロセスをシャットダウンできます。プログラムが正常に終了した場合は正常に機能しますが、クラッシュすると、すべての賭けが無効になります。

大まかな例を次に示します。

class myprocess
{
public:
    myprocess(HANDLE hProcess)
        : _hProcess(hProcess)
    { }

    ~myprocess()
    {
        TerminateProcess(_hProcess, 0);
    }

private:
    HANDLE _hProcess;
};

std::list<myprocess> allprocesses;

次に、起動するたびに、allprocessess.push_back(hProcess);を呼び出します。

于 2008-09-10T00:34:11.003 に答える