2015-04-05 4 views
2

Есть ли способ подождать синхронно для метода async, который работает в одном потоке?Подождите синхронно, чтобы асинхронный метод завершился в той же теме

желаемый эффект

  • иметь Worker() выполняются асинхронно на UI потоке
  • и в то же время ждать его, чтобы закончить перед метод Close() возвращает

Приведенный ниже пример входит в тупик, и если я создаю async 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);'. Убедитесь, что любая длинная операция, выполняемая в «Рабочем», отменяется через токен. Также уловите 'OperationCanceledException' в рабочем файле и' tcs.SetCanceled() 'в этом случае. – Alex

+0

Что вы на самом деле пытаетесь сделать? Вы сказали, что не работает над попыткой вашего решения, но вы не сказали, в чем проблема, которую вы пытаетесь решить. –

+0

Хотите, чтобы задача продолжалась, или отмените ее в любой точке прерывания, она приостановлена? –

ответ

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

+1

Это было бы немедленно убито, если вы используете 'ct.Token.ThrowIfCancellationRequested'. Вы используете его где-то? –

+0

Не знаю, но это похоже на поведение Task.ConfigureAwait (false), предложенное Алексом. – Chris

Смежные вопросы