Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing async timeout using poor mans async/await constructs in .Net 4.0

Motivation

C# 5.0 async/await constructs are awesome, unfortunately yet Microsoft only shown a release candidate of both .NET 4.5 and VS 2012, and it will take some time until these technologies will get widely adopted in our projects.

In Stephen Toub's Asynchronous methods, C# iterators, and Tasks I've found a replacement that can be nicely used in .NET 4.0. There are also a dozen of other implementations that make it possible using the approach even in .NET 2.0 though they seem little outdated and less feature-rich.

Example

So now my .NET 4.0 code looks like (the commented sections show how it is done in .NET 4.5):

//private async Task ProcessMessageAsync()
private IEnumerable<Task> ProcessMessageAsync()
{
    //var udpReceiveResult = await udpClient.ReceiveAsync();

    var task = Task<UdpAsyncReceiveResult>
               .Factory
               .FromAsync(udpClient.BeginReceive, udpClient.EndReceive, null);

    yield return task;

    var udpReceiveResult = task.Result;

    //... blah blah blah

    if (message is BootstrapRequest)
    {
        var typedMessage = ((BootstrapRequest)(message));

        // !!! .NET 4.0 has no overload for CancellationTokenSource that 
        // !!! takes timeout parameter :(
        var cts 
          = new CancellationTokenSource(BootstrapResponseTimeout); // Error here

        //... blah blah blah

        // Say(messageIPEndPoint, responseMessage, cts.Token);

        Task.Factory.Iterate(Say(messageIPEndPoint, responseMessage, cts.Token));
    }
}

Looks little ugly though it does the job

The question

When using CancellationTokenSource in .NET 4.5 there is a constructor that takes timespan as a timeout parameter, so that resulting CancellationTokenSource cancels within specified period of time.
.Net 4.0 is not able to timeout, so what is the correct way of doing that in .Net 4.0?

like image 931
Lu4 Avatar asked Jul 02 '12 20:07

Lu4


2 Answers

FWIW, you can use async/await in 4.0 projects, just use the async targeting pack. Works Great For Me!

like image 53
James Manning Avatar answered Oct 23 '22 06:10

James Manning


Does this really have anything to do with async/await? Looks like you're just needing a way to cancel the token, independently of async/await, right? In that case, could you simply create a Timer that calls Cancel after the timeout?

new Timer(state => cts.Cancel(), null, BootstrapResponseTimeout, Timeout.Infinite);

EDIT

My initial response above is the basic idea, but a more robust solution is can be found in Is CancellationTokenSource.CancelAfter() leaky? (actually the .Net 4.5 implementation of the constructor you're seeking). Here's a function you can use to create timeout tokens based on that code.

public static CancellationTokenSource CreateTimeoutToken(int dueTime) {
    if (dueTime < -1) {
        throw new ArgumentOutOfRangeException("dueTime");
    }
    var source = new CancellationTokenSource();
    var timer = new Timer(self => {
        ((Timer)self).Dispose();
        try {
            source.Cancel();
        } catch (ObjectDisposedException) {}
    });
    timer.Change(dueTime, -1);
    return source;
}
like image 27
Dax Fohl Avatar answered Oct 23 '22 06:10

Dax Fohl