これが発生したのは、 JobObjectsを使用して、C でこのコードを使用して現在のプロセスが終了したときにすべての子プロセスが終了するようにしたためです (実際には C# から p-invoke しました)。
HANDLE h = ::CreateJobObject(NULL, NULL);
JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
::ZeroMemory(&info, sizeof(info));
info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
::SetInformationJobObject(h, JobObjectExtendedLimitInformation, &info, sizeof(info));
::AssignProcessToJobObject(h, ::GetCurrentProcess());
...
::CloseHandle(h);
return -1;
このコードは、現在のプロセスとそのすべての子プロセスを、現在のプロセスの終了時に閉じられるジョブ オブジェクトに追加します。CloseHandle
しかし、呼び出されると、行に到達することなく現在のプロセスを強制終了するという副作用がありますreturn -1
。また、JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
フラグはすべてのプロセスを自動的に強制終了するため、すべてのプロセスに終了コードを設定する方法がないため、OS は終了コード 0 でプロセスを終了しました。
C# では、標準のガイドラインに従ってリソースをクリーンアップし、SafeHandle
派生クラスを使用してCloseHandle
が呼び出され、まったく同じことが起こるように::CloseHandle
しSafeHandle
ましたEnvironment.Exit
。
CloseHandle
ただし、さらに興味深いのは、C# と C++ の両方で明示的な (またはそれほど明示的ではない) への呼び出しが削除された場合でも、OS は CLR/CRT の終了後にプロセス終了時にすべてのハンドルを閉じ、実際の終了コードは返されます。したがって、リソースをクリーンアップしない方がよい場合もあります :-) つまり、ネイティブ::ExitProcess
が呼び出されるまで、終了コードが完全であることを保証できません。
したがって、この特定の問題を修正するにAssignProcessToJobObject
は、子プロセスが開始されるたびに呼び出すか、への明示的な (またはそれほど明示的ではない) 呼び出しを削除することができますCloseHandle
。私は最初のアプローチを選びました。