Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I'm hitting deadlock even after using ConfigureAwait(false), below is the sample code.

As per the sample http://blog.stephencleary.com/2012/02/async-and-await.html (#Avoding Context), this should not have hit dead lock.

This is my class:

public class ProjectsRetriever
{
    public string GetProjects()
    {
        ...
        var projects = this.GetProjects(uri).Result;
        ...
        ...
    }

    private async Task<IEnumerable<Project>> GetProjects(Uri uri)
    {
        return await this.projectSystem.GetProjects(uri, Constants.UserName).ConfigureAwait(false);
    }
}

This class is from a shared library:

public class ProjectSystem
{
    public async Task<IEnumerable<Project>> GetProjects(Uri uri, string userName)
    {
        var projectClient = this.GetHttpClient<ProjectHttpClient>(uri);
        var projects = await projectClient.GetProjects();
        // code here is never hit
        ...
}

Works if I add ConfigureAwait(false) to await call in shared library, where HttpClient call is made:

public class ProjectSystem
{
    public async Task<IEnumerable<Project>> GetProjects(Uri uri, string userName)
    {
        var projectClient = this.GetHttpClient<ProjectHttpClient>(uri);
        var projects = await projectClient.GetProjects().ConfigureAwait(false);
        // no deadlock, resumes in a new thread.
        ...
}

I've been going through all blogs found, only difference I find is ConfigureAwait(false) works when used with httpClient.AsyncApi() call!?

Please help clarify!!!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
651 views
Welcome To Ask or Share your Answers For Others

1 Answer

From the comments:

I was under assumption, once ConfigureAwait(false) is used (any where in the call stack), execution from that point will not cause deadlock.

I don't believe in black magic, and neither should you. Always strive to understand what happens when you use something in your code.

When you await an async method that returns a Task or a Task<T>, there is an implicit capture of the SynchronizationContext by the TaskAwaitable being generated by the Task.GetAwaiter method.

Once that sync context is in place and the async method call completes, the TaskAwaitable attempts to marshal the continuation (which is basically the rest of the method calls after the first await keyword) onto the SynchronizationContext (using SynchronizationContext.Post) which was previously captured. If the calling thread is blocked, waiting on that same method to finish, you have a deadlock.

You should ask yourself Should I expose synchronous wrappers for asynchronous methods? 99 percent of the time the answer is no. You should use a synchronous API, such as the one WebClient offers.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...