c# - 为什么 Main 还没有回来?

标签 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

根据 ECMA C# 语言规范的第 10.2 条“应用程序终止”:

If the return type of the entry point method is void, reaching the right brace (}) which terminates that method, or executing a return statement that has no expression, results in a termination status code of 0.

调试器确认到达正确的大括号,但标准并未明确说明离开 Main 将退出应用程序,只是设置了终止状态代码。

它还提到:

...finalizers for all of [the application's] objects that have not yet been garbage collected are called, unless such cleanup has been suppressed (by a call to the library method GC.SuppressFinalize, for example).

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

我对服务器线程可以做什么来无限期地阻止应用程序终止感到有点困惑。

最佳答案

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

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

关于c# - 为什么 Main 还没有回来?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25325798/

相关文章:

c# - 单独调用委托(delegate)?

c# - 多线程错误 : There is already an open DataReader associated with this Connection which must be closed first

c++ - C/C++ 中的内联函数是一种使它们线程安全的方法吗?

c# - 为什么 ICustomAttributeProvider.GetCustomAttributes() 返回 object[] 而不是 Attribute[]?

c# - 我想取消页面提交,在 asp.net4.0 中使用 C# 取消确认操作

java - 为什么不在构造函数中启动线程?如何终止?

.net - 取消对 "encourage".NET垃圾回收的引用有什么好处?

java - 在使用 Streams API 时使用 Chronicle Map 产生垃圾

python - 使用 .ui 文件的 PySide 小部件意外被垃圾收集

c# - Firebase 远程配置 : Version condition is disabled for Unity projects