2013-07-17 8 views
6

私はC#の中の一例の例を辿っていました。テキストによると、次のコードはブロックされていないと思われますが、フォームが5秒経過するまで表示されません。スレッドをブロックするスレッド

private void Form1_Load(object sender, EventArgs e) 
{ 
    var tcs = new TaskCompletionSource<int>(); 

    new Thread(() => {Thread.Sleep(5000); tcs.SetResult(42); }).Start(); 

    Task<int> task = tcs.Task; 
    MessageBox.Show(task.Result.ToString()); 
} 

私はそれはのThread.sleep(とは何かだ感じています)、代わりにスリープ状態に新しいスレッドを置くこと、それはスリープ状態にメインスレッドを入れています。

なぜUIスレッドをブロックしていますか?

+3

しかし、結果をすぐに使用しているので、結果が得られるまで待つことになります。 – adt

+1

このメソッドではなく、Xミリ秒で完了するタスクを取得するには、Task.Delayを使用する必要があります。両方ともより多くの仕事をしており、そこに座って何もしない(全く高価な)全く新しい仕事を作り出しています。 – Servy

+0

@Servy、 'Task.Delay()'はそこに単に置かれ、何もしません(新しいスレッドではないにもかかわらず)全く新しい 'Task'を返しますか? –

答えて

5

あなたはTaskクラス(MessageBox.Showで)Task.Result.ToString()を呼び出しタスクは、それが実際にTask終了するまでそれを持っていないので、実際に(あなたに結果を与える前に終了されるのを待つ機構を備えている。ここに私の証拠です:

private void Form1_Load(object sender, EventArgs e) 
{ 
    var tcs = new TaskCompletionSource<int>(); 

    new Thread(() => {Thread.Sleep(5000); tcs.SetResult(42); }).Start(); 

    Task<int> task = tcs.Task; 
    Thread.Sleep(2500); 
    MessageBox.Show("Waited for 2.5secs on UI thread."); 
    MessageBox.Show(task.Result.ToString()); 
} 

あなたはそれが42(その前に実際には、2.5秒)とメッセージボックスの前にあなたに2.5secメッセージボックスを示していることがわかります

何を探してるんですが、これは次のとおりです。

private void Form1_Load(object sender, EventArgs e) 
{ 
    var tcs = new TaskCompletionSource<int>(); 

    new Thread(() => {Thread.Sleep(5000); tcs.SetResult(42); }).Start(); 

    Task<int> task = tcs.Task; 
    task.ContinueWith(t => MessageBox.Show(t.Result.ToString())); 
} 

これはではなく、 UIスレッドをフリーズします。

11

タスクtask.Resultの結果を取得しようとすると、タスクが実行を終了するまで(結果が利用可能になるまで)メインスレッドがブロックされます。あなたは非同期操作の完了を待ちたくない場合はtask.ContinueWithを使用してください:

Task<int> task = tcs.Task; 
task.ContinueWith(t => {   
    MessageBox.Show(t.Result.ToString()); 
}); 

ところでタスクが完了したときに一時停止の操作を再開するための.NET 4.5での素敵な機能がある - 非同期メソッド:

private async void Form1_Load(object sender, EventArgs e) 
{ 
    var tcs = new TaskCompletionSource<int>(); 
    new Thread(() => { Thread.Sleep(2000); tcs.SetResult(42); }).Start(); 
    int result = await tcs.Task; 
    MessageBox.Show(result.ToString()); 
} 
は、

このメソッドは、タスク結果の待機を開始した直後に呼び出し元に制御を渡します。結果が利用可能になると、メソッドは実行を継続し、メッセージを表示します。

実際に@Servyがコメント内で指摘しているように、voidを返す非同期メソッドは、(エラー処理などの)非常に良い方法ではありませんが、イベントハンドラに使用することもできます。

+1

あなたの 'DoSomethingAsync'は本当に' Task'を返すべきです、 'async void'は絶対に必要なときに使うべきです、そして' Task.Delay'を使うことはその実装を劇的に簡単に、より多くの演奏者。 – Servy

+0

@Servy私は、OPがTaskCompletionSourceで実験していると思います。タスクを返すことについて同意する –

関連する問題