Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

An async/await example that causes a deadlock

I came across some best practices for asynchronous programming using c#'s async/await keywords (I'm new to c# 5.0).

One of the advices given was the following:

Stability: Know your synchronization contexts

... Some synchronization contexts are non-reentrant and single-threaded. This means only one unit of work can be executed in the context at a given time. An example of this is the Windows UI thread or the ASP.NET request context. In these single-threaded synchronization contexts, it’s easy to deadlock yourself. If you spawn off a task from a single-threaded context, then wait for that task in the context, your waiting code may be blocking the background task.

public ActionResult ActionAsync() {     // DEADLOCK: this blocks on the async task     var data = GetDataAsync().Result;      return View(data); }  private async Task<string> GetDataAsync() {     // a very simple async method     var result = await MyWebService.GetDataAsync();     return result.ToString(); } 

If I try to dissect it myself, the main thread spawns to a new one in MyWebService.GetDataAsync();, but since the main thread awaits there, it waits on the result in GetDataAsync().Result. Meanwhile, say the data is ready. Why doesn't the main thread continue it's continuation logic and returns a string result from GetDataAsync() ?

Can someone please explain me why there is a deadlock in the above example? I'm completely clueless about what the problem is ...

like image 333
Dror Weiss Avatar asked Feb 22 '13 09:02

Dror Weiss


People also ask

What is deadlock async?

The deadlock explained. The “async” and “await” keywords do not create any additional threads. Async methods are intended to be non-blocking operations. The method runs on the current “synchronization context” and uses time on the thread only when the method is active. You should use “Task.

What causes deadlocks in C#?

Deadlock occurs when a resource is locked by a thread and is required by another thread at the same time. This problem occur frequenty in a multiprocessing system. Thread One will not get Lock Q since it belongs to Thread Two.

Does async await block the thread?

The await operator doesn't block the thread that evaluates the async method. When the await operator suspends the enclosing async method, the control returns to the caller of the method.


1 Answers

Take a look at this example, Stephen has a clear answer for you:

So this is what happens, starting with the top-level method (Button1_Click for UI / MyController.Get for ASP.NET):

  1. The top-level method calls GetJsonAsync (within the UI/ASP.NET context).

  2. GetJsonAsync starts the REST request by calling HttpClient.GetStringAsync (still within the context).

  3. GetStringAsync returns an uncompleted Task, indicating the REST request is not complete.

  4. GetJsonAsync awaits the Task returned by GetStringAsync. The context is captured and will be used to continue running the GetJsonAsync method later. GetJsonAsync returns an uncompleted Task, indicating that the GetJsonAsync method is not complete.

  5. The top-level method synchronously blocks on the Task returned by GetJsonAsync. This blocks the context thread.

  6. ... Eventually, the REST request will complete. This completes the Task that was returned by GetStringAsync.

  7. The continuation for GetJsonAsync is now ready to run, and it waits for the context to be available so it can execute in the context.

  8. Deadlock. The top-level method is blocking the context thread, waiting for GetJsonAsync to complete, and GetJsonAsync is waiting for the context to be free so it can complete. For the UI example, the "context" is the UI context; for the ASP.NET example, the "context" is the ASP.NET request context. This type of deadlock can be caused for either "context".

Another link you should read: Await, and UI, and deadlocks! Oh my!

like image 143
cuongle Avatar answered Oct 09 '22 02:10

cuongle