What causes a dead end?

I ran into a deadlock issue in one piece of code. Fortunately, I was able to reproduce the problem in the example below. Running as a regular .Net Core 2.0 Console application.

class Class2 { static void Main(string[] args) { Task.Run(MainAsync); Console.WriteLine("Press any key..."); Console.ReadKey(); } static async Task MainAsync() { await StartAsync(); //await Task.Delay(1); //a little delay makes it working Stop(); } static async Task StartAsync() { var tcs = new TaskCompletionSource<object>(); StartCore(tcs); await tcs.Task; } static void StartCore(TaskCompletionSource<object> tcs) { _cts = new CancellationTokenSource(); _thread = new Thread(Worker); _thread.Start(tcs); } static Thread _thread; static CancellationTokenSource _cts; static void Worker(object state) { Console.WriteLine("entering worker"); Thread.Sleep(100); //some work var tcs = (TaskCompletionSource<object>)state; tcs.SetResult(null); Console.WriteLine("entering loop"); while (_cts.IsCancellationRequested == false) { Thread.Sleep(100); //some work } Console.WriteLine("exiting worker"); } static void Stop() { Console.WriteLine("entering stop"); _cts.Cancel(); _thread.Join(); Console.WriteLine("exiting stop"); } } 

What I expect will be the following sequence:

 Press any key... entering worker entering loop entering stop exiting worker exiting stop 

However, the actual sequence stops when Thread.Join called:

 Press any key... entering worker entering stop 

Finally, if I insert a slight delay in the body of MainAsync , everything is going well. Why is there a dead end?

NOTE: in the source code, I decided to use SemaphoreSlim instead of TaskCompletionSource , and there are no problems. I just wanted to understand where the problem is.

+5
source share
2 answers

tcs.SetResult(null); the call to Worker() will not return until the main task is completed (check this question ). In your case, the status of the WaitingForActivation task is that you get a dead end:

  • Worker() thread execution is blocked by a call to tcs.SetResult(null) .

  • Stop() thread execution is blocked by calling _thread.Join() .

+3
source

Because MainAsync() thread is "faster" than another thread. And you only manage tasks not in threads !

In your MainAsync() method, you expect the StartAsync() method to complete it, and then you will start the thread. As soon as the StartAsync() method is executed with its work (created and launched thread), this function informs MainAsync() about the completion of its work. Then MainAsync() calls the Stop method. But where is your thread? He works in parallel without any control and tries to complete his work. This is not a dead end; there is no synchronization between the task and the thread.

That's why when you put await Task.Delay(1) , your code works because the thread is fast enough to finish the job until the end of the task (thread.join).

0
source

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


All Articles