Implementing an asynchronous timeout using poor mans async / wait constructs in .Net 4.0

Motivation

The C # 5.0 async / await scripts look amazing, but unfortunately, Microsoft will only show a candidate for both .NET 4.5 and VS 2012, and it will take some time until these technologies are widely adopted in our projects.

In Stephen Toub Asynchronous Methods, C # Iterators, and Tasks I found a replacement that can be used well in .NET 4.0. There are a dozen other implementations that allow you to use the approach even in .NET 2.0, although they seem a bit outdated and less feature rich.

Example

So, now my .NET 4.0 code looks like (in the comments sections show how this 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)); } } 

It looks a little ugly, although it does the job

Question

When using CancellationTokenSource in .NET 4.5, there is a constructor that takes a period of time as a timeout parameter, so that the result of CancellationTokenSource is canceled for a certain period of time.
.Net 4.0 cannot time out, so what is the correct way to do this in .Net 4.0?

+6
source share
3 answers

Does this really have to do with async / wait? Looks like you just need a way to cancel the token, regardless of async / wait, right? In this case, could you just create a timer that calls Cancel after the timeout?

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

EDIT

My initial answer above is the main idea, but a more robust solution can be found in Is CancellationTokenSource.CancelAfter () leaky? (actually .Net 4.5 is the implementation of the constructor you are looking for). Here is a function that you can use to create timeout tokens based on this 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; } 
+4
source

FWIW, you can use async / await in 4.0 projects, just use asynchronous targeting . Works great for me!

+5
source

You can still use CancelAfter() , which is an extension method in Microsoft.Bcl.Async , which is very similar to the accepted answer above.

This is the referee suffix code when I press F12 to see the CancelAfter() implementation:

  /// <summary>Cancels the <see cref="T:System.Threading.CancellationTokenSource" /> after the specified duration.</summary> /// <param name="source">The CancellationTokenSource.</param> /// <param name="dueTime">The due time in milliseconds for the source to be canceled.</param> public static void CancelAfter(this CancellationTokenSource source, int dueTime) { if (source == null) throw new NullReferenceException(); if (dueTime < -1) throw new ArgumentOutOfRangeException("dueTime"); Contract.EndContractBlock(); Timer timer = (Timer) null; timer = new Timer((TimerCallback) (state => { timer.Dispose(); TimerManager.Remove(timer); try { source.Cancel(); } catch (ObjectDisposedException ex) { } }), (object) null, -1, -1); TimerManager.Add(timer); timer.Change(dueTime, -1); } 
0
source

Source: https://habr.com/ru/post/919526/


All Articles