I noticed this type of behavior before, and it occurred to me to ask a question this time:
I have a simple “proof of concept” program that spawns multiple threads, waits for them to do some work, and then shuts down.
But Main does not return unless I call server.Close() (which closes the socket and terminates the server thread):
private void Run() { var server = StartServer();
In accordance with Article 10.2, “End of Application,” of ECMA C # language specifications:
If the return type of the entry point method is void , reaching the right bracket ( } ) that terminates this method, or executing a return that has no expression, results in a completion status code of 0.
The debugger confirms that the right bracket is reached, but the standard does not explicitly say that leaving Main will exit the application only if the completion status code is set.
It also mentions that:
... all finalizers are called for all objects [applications] that have not yet been collected for garbage collection if such cleaning has not been suppressed (for example, by calling the library method GC.SuppressFinalize ).
I suspected that behind the scenes there might be a problem with the finalizer, since the server object implements IDisposable , and often there is a finalizer that calls Dispose . But the CLR limits the finalizers to two seconds of execution at the end of the program (in any case, something strange happens with the timeout that I tried to call GC.SuppressFinalize on the server object and got the same result).
I am a little puzzled by what the server thread can do to pause the application indefinitely.