2015-04-05 182 views
2

是否有一種方法可以同步等待在同一個線程上運行的異步方法?等待同步異步方法在同一線程上完成

所需的效果是

  • 有工人()異步UI線程
  • 上運行,並在同一時間等待它完成關閉()方法返回
之前

下面的例子進入死鎖,如果我使Form1_FormClosing()異步我不滿足第二個條件。

public partial class Form1 : Form 
{ 
    TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(); 
    CancellationTokenSource cts = new CancellationTokenSource(); 
    public Form1() 
    { 
     InitializeComponent(); 
     Show(); 
     Worker(cts.Token); // async worker started on UI thread 
    } 

    async void Worker(CancellationToken ct) 
    { 
     while (!ct.IsCancellationRequested) 
      await TaskEx.Delay(1000); 
     tcs.SetResult(true); // signal completition 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     Close(); 
     MessageBox.Show("This is supposed to be second"); 
    } 

    private async void Form1_FormClosing(object sender, FormClosingEventArgs e) 
    { 
     cts.Cancel(); // request cancel 
     tcs.Task.Wait(); // deadlock 
     await tcs.Task; // button1_Click() gets control back instead of Worker() 
     MessageBox.Show("This is supposed to be first"); 
    } 
} 
+1

使用'await Task.Delay(1000,ct).ConfigureAwait(false)'。和'tcs.TrySetResult(true);'。確保'Worker'中執行的任何長操作都可以通過令牌取消。在這種情況下,還要在worker中捕獲'OperationCanceledException',並且'tcs.SetCanceled()'。 – Alex 2015-04-05 02:17:43

+0

你究竟在做什麼?你已經說過什麼對你的解決方案沒有幫助,但是你沒有說明你想要解決的問題。 – 2015-04-05 02:34:47

+0

您是否想讓任務繼續運行,或者在任何中斷點取消它? – 2015-04-05 03:19:20

回答

3

有沒有辦法同步等待同一個線程上運行的異步方法?

您不需要同步等待。通過使Workerasync Task代替async void就可以得到所需的行爲,並刪除無用TaskCompletionSource

private Task workerTask; 
public Form() 
{ 
    workerTask = Worker(cts.Token); 
} 

private async Task Worker(CancellationToken ct) 
{ 
    while (!ct.IsCancellationRequested) 
     await TaskEx.Delay(1000); 
} 

private async void Form1_FormClosing(object sender, FormClosingEventArgs e) 
{ 
    cts.Cancel(); // request cancel 
    await workerTask; // Wait for worker to finish before closing 
} 

我失蹤的Close()執行,但我懷疑你可以沒有它,並在轉發的形式關閉事件取消工人。

+0

Close()被另一個表單調用,並且當它返回時,必須停止Worker(),否則由另一個表單修改的東西將會崩潰Worker()。亞歷克斯的建議是我正在尋找的。當我請求取消時,任務立即死亡,拋出異常,我不必擔心Worker()將訪問我即將修改的內容。 – Chris 2015-04-05 03:06:12

+1

只有使用'ct.Token.ThrowIfCancellationRequested',它纔會被立即殺死。你在某個地方使用它嗎? – 2015-04-05 03:09:54

+0

我不這樣做,但它會產生與Alex建議的Task.ConfigureAwait(false)類似的行爲。 – Chris 2015-04-05 10:48:47