Why can await Task.Delay() not return?

David Thielen 3,211 Reputation points
2024-08-03T00:12:20.7666667+00:00

Hi all;

This is not a question to fix a specific bug. This is a question where I'm trying to understand async/await better.

I hit a bug recently (details here) where the following call does not return:

await Task.Delay(1);

I clearly don't understand something about async/await because I assumed if my code is executing to the point it makes this call, then the task executing this is, prior to the call, not blocked. And a Delay(1) pauses this same task for 1 ms.

But how does the task that was running, now get blocked (not return) on this call? I'm asking not in the context of this specific bug, but how in any situation can a call to Delay() not return? I thought (and clearly I was wrong) that not returning meant something in the await called method had to be blocked thereby not allowing the task to complete..

I know my understanding is wrong. What am I not understanding about what await does in this case? I assume the Delay() completes after the 1 millisecond but in that case how can await now decide not to complete the task?

Update: Here is the specific error I hit where this occurred. Please note that having that event called in the component caused the Task.Delay(1) to never complete. Same parent component but otherwise no connection between the two.

thanks - dave

Developer technologies C#
{count} votes

Accepted answer
  1. Anonymous
    2024-08-05T09:05:22.86+00:00

    Hi @ David Thielen , Welcome to Microsoft Q&A,

    Updated by Bruce :

    Here is a good explanation:

    https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

    it does complete. it the notification of completion that is in a thread deadlock (locked thread context), which is why using .Result() is not recommended from the UI thread.

    sample UI deadlock code:

     private void btnDeadLock_Click(object sender, EventArgs e)
     {
         Func<Task<string>> DeadlockCode = async () =>
         {
             // lock context
             await Task.Delay(1000);
             return "done";
         };
    
         var value = DeadlockCode().Result;
     }
    

    a more safe way. (no deadlock):

     private void btnNoDeadLock_Click(object sender, EventArgs e)
     {
         Func<Task<string>> NoDeadlockCode = async () =>
         {
             // don't lock context
             await Task.Delay(1000).ConfigureAwait(false);
             return "done";
         };
    
         var value = NoDeadlockCode().Result;
     }
    

    note: you should fire and forget. if the UI must be updated be sure to use thread marshaling via invoke() as UI elements can only be updated from the UI thread.


    When you mark a method as async, it allows you to use the await keyword inside the method. This marking does not make the method run asynchronously by itself; it just enables the use of await.

    When you use await on a task (e.g., Task.Delay(1)), the method will asynchronously wait for that task to complete. The control is returned to the caller of the async method, and the method continues execution once the awaited task completes.

    By default, await captures the current synchronization context and tries to resume on that context. In a UI application, this means resuming on the UI thread. In a console application or background thread, it might mean resuming on the thread pool.

    If the synchronization context is busy (e.g., UI thread is blocked or doing other work), the task might not resume immediately after the delay, causing what looks like a block.

    ConfigureAwait(false)can help avoid capturing the synchronization context and prevent deadlocks.

    Best Regards,

    Jiale


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment". 

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.