Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I chain Asynchronous Operations with the Task Parallel library in .NET 4?

I'm attempting to programmatically chain asynchronous operations in C#4, such as Writes to a given Stream object. I originally did this "manually", hooking callbacks from one operation to the next, but I thought I'd try the .NET 4 Task Parallel Library to save myself the trouble of re-inventing the concurrent wheel.

To start with, I wrap my async calls in Tasks like so:

public static Task CreateWriteTask(Stream stream, byte[] data)
{
    return Task.Factory.FromAsync(stream.BeginWrite, stream.EndWrite, data, 0, data.Length, null);
}

Continuations have made chaining synchronous operations very easy (if you'll excuse the unfortunate method name):

public static Task ChainFlush(Stream stream, Task precedingTask)
{
    return precedingTask.ContinueWith(x => stream.Flush());
}

But there is no version of the Task.ContinueWith method that accepts an async operation in the same way as TaskFactory.FromAsync.

So, assuming that I persist with using the TPL, what I'm looking for the correct implementation of this method:

public static Task ChainWrite(Stream stream, byte[] data, Task precedingTask)
{
    //?
}
like image 204
FacticiusVir Avatar asked Sep 07 '10 16:09

FacticiusVir


2 Answers

My best idea so far is to chain the creation of the new write task, then use the Unwrap extension method to turn Task<Task> back into Task:

public static Task ChainWrite(Stream stream, byte[] data, Task precedingTask)
{
    return precedingTask.ContinueWith(x => CreateWriteTask(stream, data)).Unwrap();
}
like image 78
FacticiusVir Avatar answered Sep 21 '22 06:09

FacticiusVir


As far as I understand it, this is an unfortunate consequence of not being in control over when a task gets started. Since you never know when a task gets started, there can't be an overload like

precedingTask.ContinueWith(Task nextTask)

because once created, it might already be started when you get to 'ContinueWith'. Besides, it would also make a mess of types. What should be the type here:

precedingTask<T>.ContinueWith(Task<..what?..> nextTask)

preceding returns a T, so next takes what and returns what? :) This could be solved with closures though.

like image 40
Robert Jeppesen Avatar answered Sep 18 '22 06:09

Robert Jeppesen