2015-04-05 185 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