What's causing a deadlock? [duplicate] - c#

This question already has answers here:
Calling TaskCompletionSource.SetResult in a non blocking manner
(4 answers)
Closed 5 years ago.
I'm facing a deadlock-issue in a piece of code of mine. Thankfully, I've been able to reproduce the problem in the below example. Run as a normal .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'd expect is the complete sequence as follows:
Press any key...
entering worker
entering loop
entering stop
exiting worker
exiting stop
However, the actual sequence stalls on the Thread.Join call:
Press any key...
entering worker
entering stop
Finally, if I insert a small delay in the MainAsync body, everything goes fine.
Why (where) the deadlock happens?
NOTE: in the original code I solved using a SemaphoreSlim instead of a TaskCompletionSource, and there's no problems at all. I only would like to understand where the problem is.

tcs.SetResult(null); call in Worker() will not return until the underlying task is finished (check this question for details). In you case the task status is WaitingForActivation that's why you get a deadlock:
Thread executing Worker() is blocked by tcs.SetResult(null) call.
Thread executing Stop() is blocked by _thread.Join() call.

Because MainAsync() thread is 'faster' than the other thread.
And you're doing control only on tasks not on threads!
In your method MainAsync() you await method StartAsync() to finish its work and then you start the thread. Once method StartAsync() is done with its work (created and started thread) that function informs MainAsync() about finishing its work. Then MainAsync() calls Stop method.
But where is your thread? It runs in parallel without any control and tries to finish its work. This isn't deadlock, there is no synchronization between task and thread.
Thats why when you put await Task.Delay(1) your code works because thread is enough fast to finish work before task end it (thread.join).

Related

Why the async tasks not executed correctly? [duplicate]

This question already has answers here:
Running multiple async tasks and waiting for them all to complete
(10 answers)
Closed 2 years ago.
I have a project to submit job to AWS state machine and monitor the job status. So I implement the code like following pseudo code:
Two tasks are calling in the main function:
public static void Main(string[] args)
{
ExeJobs("1").Wait();
MonitorJobs().Wait();
}
In MonitoryJobs task, do something like:
public static async Task MonitorJobs()
{
int retry = 0;
for (int i = 0; i < retry; i++)
{
// Check History event here if find job id. else keep looping;
....
}
}
In ExeJobs task, do something like:
public static async Task ExeJobs(string jobId)
{
await SubmitJob(jobId);
ExecutionStatus status = ExecutionStatus.RUNNING;
while (status == ExecutionStatus.RUNNING)
{
status = await MonitorJobStaus(jobId);
}
}
I expected the MonitorJobs() is a thread keep live till I find the job execute status when it's running ExeJobs(). However it looks the MonitorJobs() task cannot start before ExeJobs() finish its while(status == ExecutionStatus.RUNNING) loop.
I wish MonitorJobs() can be running during the while loop in the other task and it should be expected result since they are two threads.
Anyone knows what's wrong here? Thanks
Wait will synchronously block until the task completes. So the current
thread is literally blocked waiting for the task to complete. As a
general rule, you should use "async all the way down"; that is, don't
block on async code.
public static async Task Main(string[] args)
{
await ExeJobs("1");
await MonitorJobs();
}
Wait will block until the task is finished. Also How your program will behave will be depended on what actually is happening inside your async tasks. You can use Task.WhenAll (making your main method async):
public static async Task Main(string[] args)
{
await Task.WhenAll(ExeJobs, MonitorJobs);
}
This will start both tasks (assuming that ExeJobs is actually asynchronous) and wait until both finish.
So you need to understand that when you await something, execution in that scope stops until the task is completed. If you want to have the execution keep going without waiting for it to finish, you need to assign it to a task and you can wait for it to finish after.
public static async Task Main(string[] args)
{
// start ExeJobs task but don't wait for it to finish
var jobTasks = ExeJobs("1");
// start monitor task but don't wait for it to finish
var monitorTask = MonitorJobs();
// wait for both tasks to finish before returning
await Task.WhenAll(jobTasks, monitorTask);
}

C# await delay not working

I want to pause the program so it does not close. I have a code running in the main thread. Tried this way, but this code instantly skips and the program closes instead of waiting.
How can I make it wait for the WaitMy method to complete?
static void Main(string[] args)
{
//any code here...
Console.WriteLine("Discovery started");
WaitMy();
}
private async static void WaitMy()
{
//await Task.Delay(30 * 1000);
await Task.Run(async () => await Task.Delay(30 * 1000));
}
The application runs with .net 4.5.
Change the code to following to make it work:
static async Task Main(string[] args)
{
//any code here...
Console.WriteLine("Discovery started");
await WaitMy();
}
How this works ?
You need C# 7.1 or later versions
Now Main method can be declared async and has return type as Task for introducing await
It will simply let the delay execute asynchronously, but will renter the main context for continuation, which will not exit
Another suggestion would be, you just need await Task.Delay(30 * 1000), wrapping inside the Task.Run is not required here
You are using Task Programming Library. What happens here is that, in your WaitMy method, you are scheduling a task to be executed (await Task.Run(...)). The task is being executed on a background thread.
In the meanwhile, the Main method continues its execution after the call to the WaitMy method.
The Main method ends right after, so the foreground thread is terminated, and all the background threads associated to its process are terminated too.
If you just want to perform a delay, just use:
System.Threading.Thread.Sleep(30 * 1000);
in the Main method, instead of calling WaitMy.
The method WaitMy can return a Task instance so you can have your main thread wait for it to be completed.
static void Main(string[] args)
{
//any code here...
Console.WriteLine("Discovery started");
var task = WaitMy();
task.Wait();
Console.WriteLine("And done :)");
}
private static Task WaitMy()
{
//await Task.Delay(30 * 1000);
return Task.Run(async () => await Task.Delay(30 * 1000));
}
If you just want the program to wait before terminating a simple answer would be to use
Console.ReadKey();
If you are curious why program terminates without waiting it is because you delegate waiting to ThreadPool by using Task.Run so waiting occurs on another thread an your application simply terminates before it can receive any result from ThreadPool

Shouldn't this answer have a try/catch for OperationCanceledException?

In this answer the code is designed to have a delay between executions on a async task.
When I implement this I have a method that will cancel the token stopping the loop. I also wait on the task so that it is finished before I continue. If I don't catch the OperationCanceledException I will wait forever, but with it it works great.
I also tried replacing the while(true) with while (!cts.IsCancellationRequested) but it didn't stop the waiting.
Am I misunderstanding the usage?
private int count = 0;
private CancellationTokenSource cts;
private Task task;
public void ContinuousWorkTask(int interval)
{
cts = new CancellationTokenSource();
// Run the import task as a async task
task = Task.Run(async () => // <- marked async
{
try {
while (true) {
DoWork();
await Task.Delay(interval, cts.Token); // <- await with cancellation
}
}
catch (OperationCanceledException) { }
}, cts.Token);
}
private void DoWork()
{
count++;
}
public void Shutdown()
{
cts.Cancel();
task.Wait(); //Without the try/catch we never stop waiting
}
Update #1: Show a very simple DoWork() to illustrate that it is not the reason the task "hangs" without the try/catch block.
Update #2: I like to wait on the task because I often have some sort of clean up to do on the way out such as writing a result to disk and I want to be sure it is done. I may do this as part of an IDisposable Dispose() method.
Update #3: It has been pointed out that the task.Wait() will receive an AggregateException. I think that adds support that the task should be catching the OperationCancelledException internally for a clean shutdown as I show in my example.
If it shouldn't I'd like to see an answer that explains why it is a better idea that I should be catching it from within the Shutdown() code. I think it is a code smell, but I may be missing a design point.

When should Task.Run() be used?

What's the difference between these two approaches:
public static int Main(string[] args)
{
string result;
Task.Run(async () =>
{
Task<string> getStringTask = GetStringAsync();
result = await validationsTask;
}).Wait();
Console.WriteLine(result);
}
and
public static int Main(string[] args)
{
Task<string> getStringTask = GetStringAsync();
getStringTask.Wait();
string result = getStringTask.Result;
Console.WriteLine(result);
}
I've seen a lot of people using the first approach and I'm not sure why. Is there any particular advantage? Which one is recommended for waiting async methods inside main of a Console Application?
Is there any particular advantage?
Usually with async methods the operation is initialized synchronously and then the wait can be asynchronous with await or syncrhnous with Wait(). The Main method can't be async so you are force to block with Wait() there or you can do a Console.ReadKey() to run until the user presses a key.
Task.Run(async () => ... ) can be quite useful when the async operation is expensive to initialize. That way you allow the main thread to continue while the operation is initializing.
Which one is recommended for waiting async methods inside main of a Console Application?
I would use a slightly modified version of the second approach. You can add a MainAsync method and call that from Main then you can use await inside it.
public static async Task MainAsync()
{
string result = await GetStringAsync();
Console.WriteLine(result);
}
public static int Main(string[] args)
{
MainAsync().Wait();
}
Also with console apps there is no risk of deadlock as there is no SynchronizationContext and the default thread pool one gets used.
The first approach continues execution after the asynch function is finished using a thread pool thread while the second approach continues execution using the calling thread that starts the asynch function.
With the second approach, there is a possibility of deadlocks. For example (similar to an example extracted from the book CLR via C#):
public static int Main(string[] args)
{
Task<string> getStringTask = GetStringAsync();
string result = getStringTask.Result; //the main thread is blocked waiting.
Console.WriteLine(result);
}
public Task<string> GetStringAsync()
{
// Issue the HTTP request and let the thread return from GetHttp
HttpResponseMessage msg = await new HttpClient().GetAsync("http://Wintellect.com/");
// We never get here: The main thread is waiting for this method to finish but this method
// can't finish because the main thread is waiting for it to finish --> DEADLOCK!
return await msg.Content.ReadAsStringAsync();
}
So the first approach avoids this problem:
public static int Main(string[] args)
{
string result;
Task.Run(async () =>
{
// We run on a thread pool thread
Task<string> getStringTask = GetStringAsync();
// We do get here because any thread pool thread can execute this code, we don't need the main thread.
result = await validationsTask;
}).Wait();
Console.WriteLine(result);
}
Another solution is using ConfigureAwait(false), extracted from the book:
Passing true to this method gives you the same behavior as not calling
the method at all. But, if you pass false, the await operator does
not query the calling thread’s SynchronizationContext object and, when
a thread pool thread completes theTask, it simply completes it and the
code after the await operator executes via the thread pool thread.
public Task<string> GetStringAsync()
{
HttpResponseMessage msg = await new HttpClient().GetAsync("http://Wintellect.com/").ConfigureAwait(false);
// We DO get here now because a thread pool can execute this code
// as opposed to forcing the main thread to execute it.
return await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
}

Task is not waiting for completion

I'm trying to get my head around await and async so I wrote this little test app, but what I expected does not happen.
Instead of waiting for the task to complete, the program continues to execute.
class Program
{
static void Main(string[] args)
{
var task = new Task(Run);
task.Start();
task.Wait();
Console.WriteLine("Main finished");
Console.ReadLine();
}
public async static void Run()
{
var task = Task.Factory.StartNew(() =>
{
Console.WriteLine("Starting");
Thread.Sleep(1000);
Console.WriteLine("End");
});
await task;
Console.WriteLine("Run finished");
}
}
Output
Main finished
Starting
End
Run finished
If I swap the 'await task' for 'task.Await()' it then runs as I would have expected producing
Starting
End
Run finished
Main finished
That is because when you have asynchronous void method, there is nothing you can do to track it's completion. Yours new Task(Run) only creates a task for starting the Run method. After the Run arrives at first await, there is nothing tracking the progress of the method, because there is nothing associated with the progress of the method. To fix it, you have to return Task instead of void and await that, instead of creating new Task.
Difference between async void and async Task is described here.

Categories

Resources