运行 方法安全取消?

Run method Safe cancellation?

我想在与 GUI 不同的线程中调用函数。

我使用了下面的代码来触发函数:

private void button1_Click(object sender, EventArgs e)
{
    tokensource = new CancellationTokenSource();
    var token = tokensource.Token;
    Task.Run(()=>foo() , token);
}

private void foo()
{
    // Uses some resources
}

private void button2_Click(object sender, EventArgs e)
{
    tokenSource.Cancel();
}

任务取消时如何安全关闭foo()中占用的资源?

您在任务中启动的代码应该负责考虑取消。您传递给 "Task.Run" 方法的取消令牌将仅用于取消未启动的任务。

您还需要将令牌传递给函数。传递给 Task.Run 的取消令牌不会中止已经 运行 的任务,它会阻止计划任务从 运行.

foo里面,可以检查token是否取消和return,或者抛出异常。您可以使用 using 块来安全地处理资源。例如:

private void foo(CancellationToken token)
{
    using(var reader=new StreamReader(somePath)
    {
            string line;
            // Read the line if no cancellation was requested
            while (!token.IsCancellationRequested && (line = sr.ReadLine()) != null) 
            {
                Console.WriteLine(line);
            }
    }
}

此代码仅在未请求取消时才读取一行,否则 return 会安静地读取一行

您还可以通过调用 CancellationToken.ThrowIfCancellationRequested

抛出 OperationCancelledException
private void foo(CancellationToken token)
{
    using(var reader=new StreamReader(somePath)
    {
            string line;
            // Read the line if no cancellation was requested
            while ((line = sr.ReadLine()) != null) 
            {
                token.ThrowIfCancellationRequested();
                Console.WriteLine(line);
            }
    }
}

这将抛出异常,当检索到任务的结果时,调用代码将引发该异常,例如使用 await Task.Run(..)Task.Run(..).Wait()

您的方法应该像这样处理 CancellationToken:

public static void Main(string[] args)
{
    var tokenSource = new CancellationTokenSource();

    Console.WriteLine("Press CTRL+C to cancel important work");

    Console.CancelKeyPress += (sender, eventArgs) => {
        eventArgs.Cancel = true;

        tokenSource.Cancel();
    };

    var task = Task.Run(() => foo(tokenSource.Token));

    task.Wait();

    WaitFor(action: "exit");
}

private static void foo(CancellationToken token)
{
    const int Times = 10;

    for (var x = 0; x < Times && token.IsCancellationRequested == false; ++x) {
        Console.WriteLine("Important work");

        Task
            .Delay(200)
            .Wait();
    }

    Console.WriteLine($"Free resources: {token.IsCancellationRequested}");
}

public static void WaitFor(ConsoleKey consoleKey = ConsoleKey.Escape, string action = "continue")
{
    Console.Write($"Press {consoleKey} to {action} ...");

    var consoleKeyInfo = default(ConsoleKeyInfo);

    do {
        consoleKeyInfo = Console.ReadKey(true);
    }
    while (Equals(consoleKeyInfo.Key, consoleKey) == false);

    Console.WriteLine();
}

BR incureforce