如何正常取消异步工作?

时间:2014-03-13 11:54:03

标签: c# .net events asynchronous async-await

我有一个UI应用程序,每秒都会记录一些内容。每次OpenFileHandler被触发时,我都必须开始记录到新文件。这是代码的一个非常简化的版本:

string _logItem;
string _fileName;
CancellationTokenSource _cts;
Task _task;

private void OpenFileHandler(object sender, EventArgs e)
{
    // once OpenFileHandler has been fired, 
    // the _logItem should go to the new file

    if (_task != null && !_task.IsCompleted)
    {
        _cts.Cancel();
        // can't do: _task.Wait();
    }

    if ( _fileName != null )
    {
       _cts = new CancellationTokenSource();
       _task = LogAsync(_fileName, _cts.Token);
    }
}

private async Task LogAsync(string fileName, CancellationToken ct)
{
    using (var writer = new System.IO.StreamWriter(fileName, false))
    {
        try
        {
            while (true)
            {
                await Task.Delay(1000, ct);
                await writer.WriteLineAsync(_logItem);
            }
        }
        finally
        {
            writer.WriteLine("end of log!");
        }
    }
}

问题:OpenFileHandler是同步的,但在开始新的WriteLineAsync任务之前,我需要确保挂起的LogAsync已完成且旧的日志文件已关闭

我无法在_task.Wait()内执行OpenFileHandler因为它会阻止UI线程。

我也无法使OpenFileHandler成为async方法并在其中执行await _task。这是因为当应用程序关闭时,OpenFileHandler_fileName null触发,我希望"end of log!"行仍然在日志中。

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:3)

作为LogAsync的第一行,等待旧任务:

await prevTask;

你需要传递上一个任务。也许作为方法论证。

您可能需要抓住OperationCancelledException或:

await prevTask.ContinueWith(_ => { }); //suppress exceptions

答案 1 :(得分:0)

你能不能处理关闭应用程序的特殊情况(并将null传递给OpenFileHandler方法)?

因此,在应用程序关闭的情况下,您_cts.Cancel()然后_task.Wait()以允许日志完成写入。

而不是while(true)无法检查CancellationToken是否已被取消,如果它已经退出并写下'结束日志!'