运行方法安全取消?

时间:2017-05-30 07:14:48

标签: c# 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()中的已占用资源?

3 个答案:

答案 0 :(得分:2)

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

foo内,您可以检查令牌是否取消并返回,或者抛出异常。您可以使用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);
            }
    }
}

此代码仅在未请求取消时读取一行,否则将安静地返回

您也可以通过调用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()

答案 1 :(得分:1)

你的方法应该像这样处理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

答案 2 :(得分:0)

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