2

コード内で明示的に -1 を返しているにもかかわらず、C# アプリケーションはコード 0 で終了します。

internal class Program
{
    public int Main()
    {
        ....
        return -1;
    }
}

が使用された場合も同じことが起こりましたvoid Main

internal class Program
{
    public void Main()
    {
        ....
        Environment.Exit(-1);
    }
}

SOに関する他の質問が示唆したように、他のスレッドで未処理のCLR/C++/ネイティブ例外であった可能性があります。ただし、この最後のスレッドの直前に、すべてのマネージド/ネイティブ スレッドの正常なシャットダウンを追加しましたが、動作は維持されました。

その理由は何ですか?

4

1 に答える 1

2

これが発生したのは、 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が呼び出され、まったく同じことが起こるように::CloseHandleSafeHandleましたEnvironment.Exit

CloseHandleただし、さらに興味深いのは、C# と C++ の両方で明示的な (またはそれほど明示的ではない) への呼び出しが削除された場合でも、OS は CLR/CRT の終了後にプロセス終了時にすべてのハンドルを閉じ、実際の終了コードは返されます。したがって、リソースをクリーンアップしない方がよい場合もあります :-) つまり、ネイティブ::ExitProcessが呼び出されるまで、終了コードが完全であることを保証できません。

したがって、この特定の問題を修正するにAssignProcessToJobObjectは、子プロセスが開始されるたびに呼び出すか、への明示的な (またはそれほど明示的ではない) 呼び出しを削除することができますCloseHandle。私は最初のアプローチを選びました。

于 2013-10-09T23:46:05.767 に答える