为什么Main不归?

Sel*_*bor 5 c# multithreading garbage-collection deadlock terminate

之前我已经注意到了这种行为,这次我想问一个问题:

我有一个简单的"概念证明"程序,它产生一些线程,等待它们做一些工作,然后退出.

但是Main除非我调用server.Close()(关闭套接字并结束服务器线程的执行),否则不返回:

private void Run()
{
    var server = StartServer(); //Starts a thread in charge of listening on a socket

    _serverResetEvent.WaitOne();

    ThriftProtocolAccessManager protocolManager = CreateProtocolManager(); //Doesn't create any threads

    const int numTestThreads = 10;

    Barrier testCompletedBarrier;

    Thread[] testThreads = GenerateTestThreads(numTestThreads, protocolManager, out testCompletedBarrier); //Creates x threads, where x is numTestThreads

    testThreads
        .AsParallel()
        .ForAll(thread => thread.Start()); //Start them "at the same time" (For testing purposes 

    testCompletedBarrier.SignalAndWait(); //Barrier has participants equal to numTestThreads + 1 and each thread calls this
    //server.Close() would go here. When it is here, the program returns as expected
    Console.WriteLine("All Threads Complete"); //This is getting called
}
private static void Main(string[] args)
{
    new Program().Run();
    Console.WriteLine("Run completed"); //This is also called
}//The debugger confirms this brace is reached as well
Run Code Online (Sandbox Code Playgroud)

根据第10.2条,ECMA C#语言规范的"申请终止":

如果入口点方法的返回类型是void,到达}终止该方法的右大括号(),或执行return没有表达式的语句,则导致终止状态代码为0.

调试器确认正在到达右括号,但标准没有明确表示离开Main将退出应用程序,只是设置了终止状态代码.

它还提到:

...调用尚未被垃圾回收的所有[应用程序]对象的终结器,除非已经抑制了这种清理(例如,通过调用库方法GC.SuppressFinalize).

我怀疑在幕后终结器可能是问题,因为服务器对象实现了IDisposable,并且有一个终结器调用的情况并不少见Dispose.但是当程序被终止时,CLR将终结器限制为执行两秒钟(以防万一有些奇怪的事情发生在超时我尝试调用GC.SuppressFinalize服务器对象并得到相同的结果).

我有点难过服务器线程可以做什么来无限期地终止应用程序的终止.

Sel*_*bor 0

@Carsten K\xc3\xb6nig 的链接中使用的措辞让我意识到我正在查找错误的文档。问题确实是启动服务器实现的线程是前台线程,将其更改为后台线程会导致 ThreadPool 实现按预期运行。

\n\n

ECMA 标准似乎推迟了特定的终止行为(CLI 文档也没有提及任何相关内容)。我仍在寻找是否可以找到一份更详细地描述整个终止程序的通用文档。

\n