.netwpfasync-awaitdispatcher

Call async methods from Dispatcher.Invoke()?


Can this kind of code bring trouble (e.g. deadlocks) or will it work as intended:

void CalledFromAnotherThread()
{
   Dispatcher.CurrentDispatcher.Invoke(DoUiStuff)
}

async Task DoUiStuff()
{
    await DoAsyncStuff();
}

When I am not awaiting DoUiStuff at all, should I make it return void then?


Solution

  • Yes, that's a common reason for deadlocks, if the UI thread is waiting for the background operation to complete. The question Deadlock when thread uses dispatcher and the main thread is waiting for thread to finish demonstrate this. To avoid this before 2012 the solution was to use BeginInvoke.

    I'd try to avoid calling Dispatcher.Invoke altogether. This couples frontend and backend code and results in more complex code. I'd try to break the operations on parts that work on the background, await them with await and perform any UI modifications in between.

    From the comments, it looks like CalledFromAnotherThread is a callback. Callbacks and events can be converted to tasks using TaskCompletionSource, eg :

    async Task DoSomethingAsync()
    {
        var tcs=new TaskCompletionSource<bool>();
    
        _whatever.MyCallBack= ok=>{
            if(ok){
                tcs.SetResult(true);
            }
            else {
                tcs.SetException(...something...);
            }
        });
        _whatever.StartLongJob();
        return tcs.Task;
    }
    

    You can await DoSomethingAsync async now, like any other asynchronous call.

    await DoSomethingAsync();
    DoUiStuff();
    await DoOtherAsyncStuff();