Coder Perfect

When should you use TaskCompletionSourceT>?

Problem

All it knows, AFAIK, is that its SetResult or SetException method is being called at some time in order to complete the TaskT> supplied by its Task property.

In other words, it produces a TaskTResult> and ensures that it is completed.

Here’s an example of what I’m talking about:

public static Task<T> RunAsync<T>(Func<T> function) 
{ 
    if (function == null) throw new ArgumentNullException(“function”); 
    var tcs = new TaskCompletionSource<T>(); 
    ThreadPool.QueueUserWorkItem(_ => 
    { 
        try 
        {  
            T result = function(); 
            tcs.SetResult(result);  
        } 
        catch(Exception exc) { tcs.SetException(exc); } 
    }); 
    return tcs.Task; 
}

Which could be used if Task.Factory.StartNew wasn’t available, but I do have Task.Factory.StartNew.

Question:

Can someone please clarify a scenario that is directly relevant to TaskCompletionSource and not a hypothetical circumstance in which I don’t have Task.Factory.StartNew by way of example?

Asked by Royi Namir

Solution #1

When just an event-based API is provided (for example, Windows Phone 8 connections), I usually use it:

public Task<Args> SomeApiWrapper()
{
    TaskCompletionSource<Args> tcs = new TaskCompletionSource<Args>(); 

    var obj = new SomeApi();

    // will get raised, when the work is done
    obj.Done += (args) => 
    {
        // this will notify the caller 
        // of the SomeApiWrapper that 
        // the task just completed
        tcs.SetResult(args);
    }

    // start the work
    obj.Do();

    return tcs.Task;
}

As a result, it’s particularly handy when combined with the C#5 async keyword.

Answered by GameScripting

Solution #2

TaskCompletionSource, in my experience, works well for wrapping old asynchronous patterns in the contemporary async/await paradigm.

Working with Socket is the most useful example I can think of. It has the old APM and EAP patterns, but not the TcpListener and TcpClient’s awaitable Task methods.

I dislike the NetworkStream class for various reasons and prefer the bare Socket. Because I enjoy the async/await paradigm, I created the SocketExtender extension class, which adds various extension methods to Socket.

To wrap the asynchronous calls, all of these methods use TaskCompletionSourceT> as follows:

    public static Task<Socket> AcceptAsync(this Socket socket)
    {
        if (socket == null)
            throw new ArgumentNullException("socket");

        var tcs = new TaskCompletionSource<Socket>();

        socket.BeginAccept(asyncResult =>
        {
            try
            {
                var s = asyncResult.AsyncState as Socket;
                var client = s.EndAccept(asyncResult);

                tcs.SetResult(client);
            }
            catch (Exception ex)
            {
                tcs.SetException(ex);
            }

        }, socket);

        return tcs.Task;
    }

I pass the socket into the BeginAccept methods so that the compiler doesn’t have to hoist the local parameter. This gives me a minor performance benefit.

Then there’s the sheer joy of it:

 var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 listener.Bind(new IPEndPoint(IPAddress.Loopback, 2610));
 listener.Listen(10);

 var client = await listener.AcceptAsync();

Answered by Erik

Solution #3

A classic use case for TaskCompletionSource, in my opinion, is when it’s possible that my function won’t have to do a time-consuming task. It allows us to pick and choose which situations we’d like to use a new thread in.

When you use a cache, this is a nice illustration. You can have a GetResourceAsync function that searches the cache for the requested resource and returns immediately (without spawning a new thread, thanks to TaskCompletionSource). We’d like to create a new thread and fetch the resource using Task only if the resource was not found. Run().

How to conditionally run a code asynchonously using tasks is an example of code.

Answered by Adi Lester

Solution #4

Levi Botelho explains how to use the TaskCompletionSource to create an asynchronous wrapper for a Process so that you can start it and wait for it to finish in this blog article.

public static Task RunProcessAsync(string processPath)
{
    var tcs = new TaskCompletionSource<object>();
    var process = new Process
    {
        EnableRaisingEvents = true,
        StartInfo = new ProcessStartInfo(processPath)
        {
            RedirectStandardError = true,
            UseShellExecute = false
        }
    };
    process.Exited += (sender, args) =>
    {
        if (process.ExitCode != 0)
        {
            var errorMessage = process.StandardError.ReadToEnd();
            tcs.SetException(new InvalidOperationException("The process did not exit correctly. " +
                "The corresponding error message was: " + errorMessage));
        }
        else
        {
            tcs.SetResult(null);
        }
        process.Dispose();
    };
    process.Start();
    return tcs.Task;
}

and its usage

await RunProcessAsync("myexecutable.exe");

Answered by Sarin

Solution #5

When creating Task objects that don’t run code, TaskCompletionSource is used. TaskCompletionSource is excellent for I/O bound processes in real-world contexts. You get all of the benefits of tasks (such return values, continuations, and so on) without stopping a thread for the length of the operation. It is not suggested to use a new Task to stop a thread if your “function” is an I/O bound operation. Instead, you can establish a slave task using TaskCompletionSource to simply indicate when your I/O-bound process completes or fails.

Answered by v1p3r

Post is based on https://stackoverflow.com/questions/15316613/when-should-taskcompletionsourcet-be-used