Search code examples
c#multithreadingasynchronoustask-parallel-libraryasync-await

Calling TaskCompletionSource.SetResult in a non blocking manner


I've discovered that TaskCompletionSource.SetResult(); invokes the code awaiting the task before returning. In my case that result in a deadlock.

This is a simplified version that is started in an ordinary Thread

void ReceiverRun()
    while (true)
    {
        var msg = ReadNextMessage();
        TaskCompletionSource<Response> task = requests[msg.RequestID];

        if(msg.Error == null)
            task.SetResult(msg);
        else
            task.SetException(new Exception(msg.Error));
    }
}

The "async" part of the code looks something like this.

await SendAwaitResponse("first message");
SendAwaitResponse("second message").Wait();

The Wait is actually nested inside non-async calls.

The SendAwaitResponse(simplified)

public static Task<Response> SendAwaitResponse(string msg)
{
    var t = new TaskCompletionSource<Response>();
    requests.Add(GetID(msg), t);
    stream.Write(msg);
    return t.Task;
}

My assumption was that the second SendAwaitResponse would execute in a ThreadPool thread but it continues in the thread created for ReceiverRun.

Is there anyway to set the result of a task without continuing its awaited code?

The application is a console application.


Solution

  • Use var tcs = new TaskCompletionSource<Response>(TaskCreationOptions.RunContinuationsAsynchronously); when you want to force continuations added to the current task to be executed asynchronously.