Why is Home not coming back?

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(); //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 

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.

+5
source share
1 answer

The words used in the @Carsten König link lead me to realize that I was looking for the wrong documentation. The problem is that the thread that started the server implementation was the front thread, changing it to a background thread, forcing the ThreadPool implementation to behave as expected.

The ECMA standard seems to override the specific termination behavior (nothing was mentioned in the CLI documentation). I am still looking to see if I can find a general document that describes the entire completion procedure in more detail.

0
source

Source: https://habr.com/ru/post/1200408/


All Articles