プロセスの終了

プロセスを終了すると、次の結果が得られます。

  • プロセス内の残りのスレッドはすべて終了のマークが付けられます。
  • プロセスによって割り当てられたリソースはすべて解放されます。
  • すべてのカーネル オブジェクトが閉じられます。
  • プロセス コードがメモリから削除されます。
  • プロセス終了コードが設定されます。
  • プロセス オブジェクトが通知されます。

カーネル オブジェクトに対する開いているハンドルは、プロセスが終了すると自動的に閉じられますが、オブジェクト自体は、開いているすべてのハンドルが閉じられるまで存在します。 したがって、オブジェクトは、別のプロセスが開いているハンドルを持っている場合、それを使用しているプロセスが終了した後も有効なままになります。

GetExitCodeProcess 関数は、プロセスの終了状態を返します。 プロセスの実行中、終了状態はSTILL_ACTIVE。 プロセスが終了すると、その終了状態がSTILL_ACTIVEからプロセスの終了コードに変わります。

プロセスが終了すると、プロセス オブジェクトの状態がシグナル通知され、プロセスの終了を待機していたスレッドが解放されます。 同期の詳細については、「 複数スレッドの実行の同期」を参照してください。

システムは、プロセスを終了する際に、プロセスが作成した子プロセスを終了しません。 プロセスを終了しても、WH_CBTフック プロシージャの通知は生成されません。

SetProcessShutdownParameters 関数を使用して、システムシャットダウン時のプロセス終了の特定の側面 (システム内の他のプロセスに対してプロセスを終了するタイミングなど) を指定します。

プロセスの終了方法

プロセスは、次のいずれかのイベントが発生するまで実行されます。

  • プロセスのすべてのスレッドが ExitProcess 関数を呼び出します。 C ランタイム ライブラリ (CRT) の実装によっては、プロセスのプライマリ スレッドが返された場合に ExitProcess が呼び出されることに注意してください。
  • プロセスの最後のスレッドが終了します。
  • すべてのスレッドは、プロセスへのハンドルを使用して TerminateProcess 関数を呼び出します。
  • コンソール プロセスの場合、コンソールが Ctrl + C または Ctrl + BREAK シグナルを受信すると、既定の コンソール コントロール ハンドラーExitProcess を呼び出します。
  • ユーザーがシステムをシャットダウンするか、ログオフします。

スレッドが既知の状態でない限り、プロセスを終了しないでください。 スレッドがカーネル オブジェクトで待機している場合、待機が完了するまで終了しません。 これにより、アプリケーションが応答を停止する可能性があります。

プライマリ スレッドは、プロセスを終了させる前に ExitThread を呼び出すように指示することで、他のスレッドの終了を回避できます (詳細については、「 スレッドの終了」を参照してください)。 プライマリ スレッドは、その後も ExitProcess を 呼び出して、すべてのスレッドが終了することを確認できます。

プロセスの終了コードは、ExitProcess または TerminateProcess の呼び出しで指定された値、またはプロセスのメイン関数または WinMain 関数によって返される値のいずれかです。 致命的な例外が原因でプロセスが終了した場合、終了コードは終了の原因となった例外の値です。 さらに、この値は、例外が発生したときに実行されていたすべてのスレッドの終了コードとして使用されます。

プロセスが ExitProcess によって終了した場合、システムは、プロセスが DLL からデタッチされていることを示す値を使用して、アタッチされている各 DLL のエントリ ポイント関数を呼び出します。 プロセスが TerminateProcess によって終了された場合、DLL には通知されません。 DLL の詳細については、「 ダイナミック リンク ライブラリ」を参照してください。

プロセスが TerminateProcess によって終了された場合、プロセスのすべてのスレッドは、追加のコードを実行する機会なしですぐに終了します。 つまり、スレッドは終了ハンドラー ブロックでコードを実行しません。 さらに、アタッチされている DLL には、プロセスがデタッチ中であることが通知されません。 あるプロセスで別のプロセスを終了させる必要がある場合は、次の手順を実行すると、より優れたソリューションが得られます。

  • 両方のプロセスで RegisterWindowMessage 関数を呼び出してプライベート メッセージを作成します。

  • 1 つのプロセスは、 BroadcastSystemMessage 関数を使用してプライベート メッセージをブロードキャストすることで、もう一方のプロセスを終了できます。

     DWORD dwRecipients = BSM_APPLICATIONS;
        UINT uMessage = PM_MYMSG;
        WPARAM wParam = 0;
        LPARAM lParam = 0;
    
        BroadcastSystemMessage( 
            BSF_IGNORECURRENTTASK, // do not send message to this process
            &dwRecipients,         // broadcast only to applications
            uMessage,              // registered private message
            wParam,                // message-specific value
            lParam );              // message-specific value
    
  • プライベート メッセージを受信するプロセスは 、ExitProcess を 呼び出して実行を終了します。

ExitProcessExitThreadCreateThreadCreateRemoteThread、および CreateProcess 関数の実行は、アドレス空間内でシリアル化されます。 次の制限事項が適用されます。

  • プロセスの起動時と DLL 初期化ルーチンでは、新しいスレッドを作成できますが、プロセスの DLL 初期化が完了するまで実行は開始されません。
  • DLL 初期化ルーチンまたはデタッチ ルーチンに含めることができるスレッドは一度に 1 つだけです。
  • ExitProcess 関数は、DLL 初期化ルーチンまたはデタッチ ルーチンにスレッドが存在しない限り、戻りません。