6

動機

C#5.0の非同期/待つ構築物は、素晴らしいです、残念ながらまだマイクロソフトが唯一の.NET 4.5とVS 2012の両方のリリース候補を示し、そしてそれこれらの技術が我々のプロジェクトに広く採用されるまでには時間がかかるだろう。貧しいマンの非同期/を使用して非同期タイムアウトを実装する構造を待つ

私はきれいに.NET 4.0で使用可能な代替を見つけたスティーブンToubの Asynchronous methods, C# iterators, and Tasks

。 .NET 2.0でもアプローチを使用することが可能な他の実装が十数ありますが、古くて機能が豊富ではないようです。

は、だから今、私の.NET 4.0のコードは次のようになります(コメントのセクションでは、それは.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)); 
    } 
} 

は少し醜い

質問

.NET 4.5にCancellationTokenSourceを使用する場合、timespanをタイムアウトパラメータとするコンストラクタがあり、その結果、CancellationTokenSourceは、指定した時間内にキャンセルします。
.Net 4.0はタイムアウトすることができません.Net 4.0ではこれを行う正しい方法は何ですか?

+0

関連の質問:http://stackoverflow.com/questions/9110472/using-async-await-on- net-4 – CodesInChaos

+0

タイトルがタイムアウトし、タイマー(一部の期間の実行で定期的に使用される)が誤解を招き混乱していたため、タイトルの「タイマー」を「タイムアウト」に変更しました –

答えて

4

これは本当に/待って非同期とは何かを持っていますか? async/awaitとは関係なくトークンをキャンセルする方法が必要なようですね。その場合、タイムアウト後にCancelを呼び出すTimerを作成するだけですか?上記

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

EDIT

私の最初の反応は、基本的な考え方ですが、より堅牢なソリューションをIs CancellationTokenSource.CancelAfter() leaky?(あなたが探しているコンストラクタの実際の.Net 4.5実装)で見つけることができています。ここに、そのコードに基づいてタイムアウトトークンを作成するために使用できる関数があります。

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; 
} 
+0

どのようなタイマーをDaxを使う? – Lu4

+0

'System.Threading.Timer'は私が考えていたものですが、そのうちのどれかがうまくいくと思っています。私はさまざまな種類の.Net 'Timer'の違いについて専門家ではありません。 –

+0

しかし、それはスレッドをブロックし、非同期的なアプローチのすべての利点を失うことになるでしょう:( – Lu4

5

FWIWでは、4.0プロジェクトでasync/awaitを使用できます。ちょうどthe async targeting packを使用してください。私にとって素晴らしい作品です!

+1

確かに有益な回答 – Lu4

0

あなたはまだ上記の受け入れ答えに非常に似てMicrosoft.Bcl.Asyncで拡張メソッドがあるCancelAfter()を、使用することができます。

私はCancelAfter()の実装を確認するためにF12を押したときにこれがrefereanceの源泉コードです:

/// <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); 
    } 
関連する問題