c# - 如何通过 CancellationToken 停止异步进程?

标签 c# async-await cancellation

我在代码下方找到了执行某些进程而不卡住 UI 的代码。按下“开始工作”按钮时执行此代码。而且我认为用户会通过“停止”按钮停止这项工作。所以我在 MSDN 上找到了这篇文章.. https://msdn.microsoft.com/en-us/library/jj155759.aspx .但是,很难应用这个 CancellationToken在此代码..任何人都可以解决这个问题吗?

我使用 public static async Task<int> RunProcessAsync(string fileName, string args)仅方法。

代码(来自 https://stackoverflow.com/a/31492250 ):

public static async Task<int> RunProcessAsync(string fileName, string args)
{
    using (var process = new Process
    {
        StartInfo =
        {
            FileName = fileName, Arguments = args,
            UseShellExecute = false, CreateNoWindow = true,
            RedirectStandardOutput = true, RedirectStandardError = true
        },
        EnableRaisingEvents = true
    })
    {
        return await RunProcessAsync(process).ConfigureAwait(false);
    }
}

// This method is used only for internal function call.
private static Task<int> RunProcessAsync(Process process)
{
    var tcs = new TaskCompletionSource<int>();

    process.Exited += (s, ea) => tcs.SetResult(process.ExitCode);
    process.OutputDataReceived += (s, ea) => Console.WriteLine(ea.Data);
    process.ErrorDataReceived += (s, ea) => Console.WriteLine("ERR: " + ea.Data);

    bool started = process.Start();
    if (!started)
    {
        //you may allow for the process to be re-used (started = false) 
        //but I'm not sure about the guarantees of the Exited event in such a case
        throw new InvalidOperationException("Could not start process: " + process);
    }

    process.BeginOutputReadLine();
    process.BeginErrorReadLine();

    return tcs.Task;
}

用法:

var cancelToken = new CancellationTokenSource();
int returnCode = async RunProcessAsync("python.exe", "foo.py", cancelToken.Token);
if (cancelToken.IsCancellationRequested) { /* something */ }

单击开始按钮时,它会启动一些 python 脚本。 当脚本正在运行并且用户想要停止它时,用户按下停止按钮。 然后程序执行下面的代码。

cancelToken.Cancel();

非常感谢您阅读这个问题。

最佳答案

简单的答案是,您可以在 token 被取消时调用 process.Kill():

cancellationToken.Register(() => process.Kill());

但这有两个问题:

  1. 如果您试图终止一个尚不存在或已经终止的进程,您将得到一个InvalidOperationException
  2. 如果您不Dispose() Register() 返回的CancellationTokenRegistrationCancellationTokenSource是长期存在的,你有内存泄漏,因为只要 CancellationTokenSource,注册就会保留在内存中。

根据您的要求和您对干净代码的渴望(即使以复杂性为代价),忽略问题 #2 并通过在 catch 中吞下异常来解决问题 #1 可能是可以的>.

关于c# - 如何通过 CancellationToken 停止异步进程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34199628/

相关文章:

c# - 如何以通用方式耦合两个类?

php - 在 MySQL InnoDB 中取消事务而不是提交或回滚

c# - Linq - 不以前缀范围内的任何前缀开头

c# - 更改 Chart Winforms 上的轴值

c# - 等待的任务不异步运行

async-await - 配置等待的静态分析

Javascript异步如何等待不同数量的uploadTasks全部完成?

c - 如果在取消点调用信号处理程序会发生什么?

c# - 如何在 MassTransit ESB 中取消与 CancellationToken 的请求/响应通信?

c# - 在另一个表格中设置表格宽度未反射(reflect)在创建的 pdf 中