Search code examples
c#.netmultithreading.net-coretaskcompletionsource

How to continue TaskCompletionSource<> in another thread?


I'm using TaskCompletionSource<> quite often. I have a network protocol design, where I receive many streams in one tcp/ip connection. I demultiplex those streams and then inform the corresponding "SubConnections" of new content.

Those "SubConnections" (which are waiting via await) then should continue in a new thread.

Usually I solve such issues by putting the TaskComplectionSource<>.Set call in an anonymous ThreadPool.QueueUserWorkItem method, like this:

ThreadPool.QueueUserWorkItem(delegate { tcs.SetResult(null); });

If I don't do this the corresponding await tcs.Task call will continue in the thread which called tcs.SetResult.

However, I'm aware of that this isn't the right way to do things. It's also possible to self-write a SynchronizationContext (or something) which will instruct the await call to continue in another thread.

My primary question here is: How would I do this in the "best practice" way?

My hope here is also to avoid the ThreadPool overhead, because it's quite high on Linux compared to just blocking a thread and waiting for a ManualResetEvent - even though the SynchronizationContext (or whatever) may also utilize the ThreadPool.

Please refrain from telling me that it's generally a bad idea to multiplex something in one tcp/ip connection or that I should just use System.IO.Pipelines, REST or whatever. This is my scenario. Thank you.


Solution

  • You can create the TaskCompletionSource using TaskCreationOptions.RunContinuationsAsynchronously (in .NET 4.6+):

    var tcs = new TaskCompletionSource<Result>(TaskCreationOptions.RunContinuationsAsynchronously);
    ...
    tcs.SetResult(...);
    

    See e.g. this thread for more details.