Pergunta

Trying to learn Task, Wait and Cancellation.
Started with what I thought was a simple sample from MSDN.
Task.Wait Method (CancellationToken)

As a console application this runs as expected.
That same code does not run as expected in WPF.
In WPF t2 Runs to completion - the line Task finished is printed in debug.
It hits the OperationCanceledException between 0 and 100000000 but t2 keeps on running.
(note had to change it to ctr < Int32.MaxValue or it would never finish)

On .NET 4.5 and also tried 4.51

public void TestCancel1()
{
    CancellationTokenSource cts = new CancellationTokenSource();
    CancellationToken token = cts.Token;

    Task.Run(() =>
    {
        cts.Cancel();
        if (token.IsCancellationRequested)
            Debug.WriteLine("Cancellation requested in Task {0}.",
                                Task.CurrentId);
    }, token);
    Task t2 = Task.Run(() =>
    {
        Debug.WriteLine(Int32.MaxValue.ToString());
        for (Int32 ctr = 0; ctr < Int32.MaxValue; ctr++)  // 
        {
            if (ctr % 100000000 == 0)
                Debug.WriteLine(ctr.ToString());
        }
        Debug.WriteLine("Task {0} finished.",
                            Task.CurrentId);
    });
    try
    {
        t2.Wait(token);
    }
    catch (OperationCanceledException)
    {
        Debug.WriteLine("OperationCanceledException in Task {0}: The operation was cancelled.", 
                         t2.Id);
    }
}

there have been question on the console app
here is the code

static void Main(string[] args)
{
    CancellationTokenSource cts = new CancellationTokenSource();
    CancellationToken token = cts.Token;

    Task.Run(() =>
    {
        Thread.Sleep(1000);  // change number and will get a differnt last ctr
        cts.Cancel();
        if (token.IsCancellationRequested)
            Console.WriteLine("Cancellation requested in Task {0}.",
                                Task.CurrentId);
    }, token);
    Task t2 = Task.Run(() =>
    {
        Console.WriteLine(Int32.MaxValue.ToString());
        for (int ctr = 0; ctr < Int32.MaxValue; ctr++)
        {
            Console.WriteLine(ctr.ToString());
            if (ctr % 100000000 == 0) Console.WriteLine(ctr.ToString());
        }
        Console.WriteLine("Task {0} finished.",
                            Task.CurrentId);
    });
    try
    {
        t2.Wait(token);
    }
    catch (OperationCanceledException)
    {
        Console.WriteLine("OperationCanceledException in Task {0}: The operation was cancelled.",
                            t2.Id);
    }
}

Added the ThrowIfCancellationRequested
I am getting an error on that line OperationCancelException was unhandled by user code

Task t2 = Task.Run(() =>
{
    Debug.WriteLine(Int32.MaxValue.ToString());
    for (Int32 ctr = 0; ctr < Int32.MaxValue; ctr++)  // 
    {                   
        if (ctr % 100000000 == 0)
        {
            Debug.WriteLine(ctr.ToString() + " " + token.IsCancellationRequested.ToString());
        }
        if (token.IsCancellationRequested)
            token.ThrowIfCancellationRequested();
    }
    Debug.WriteLine("Task {0} finished.",
                        Task.CurrentId);
}); //, token);

OK I know this is getting long
That sample from Microsoft is misleading at best - why would you have a sample for Cancel that does not really cancel
To verify why Rohit stated I added the following
And sure enough I could see some more passes before the press any key to continue

    catch (OperationCanceledException)
    {               
        Console.WriteLine("OperationCanceledException in Task {0}: The operation was cancelled.",
                            t2.Id);
        Thread.Sleep(10);
        Console.WriteLine("exit exception");
    }
Foi útil?

Solução 2

This is not related to WPF. Output will be same for Console application, WPF or WinForms.

As a console application this runs as expected. That same code does not run as expected in WPF. In WPF t2 Runs to completion - the line Task finished is printed in debug.

I suspect in console application you tested with ctr <= Int32.MaxValue that's why Finised is not printed because it runs infinitely and Finish never gets printed on console.


It hits the OperationCanceledException between 0 and 100000000 but t2 keeps on running.

Exception won't stop task t2 from executing to finish at all.

OperationCanceledException gets thrown on main thread because you ask main thread to wait on task t2 and pass cancellation token. So, with catching this exception your main thread is no longer waiting on task t2 to complete but that doesn't mean task t2 will be stopped. It will run to its complete execution. Also, main thread is now free to continue with its further execution.

This brings me to another conclusion that you might be missing Console.ReadKey() in Main method. That's why your console application close once exception gets thrown (main thread is not waiting anymore on task t2). Hence, you never see Finish to be printed on Console (assuming you run loop with ctr < Int32.MaxValue).

If you want task t2 to be stopped you can call token.ThrowIfCancellationRequested(); which will cause task t2 to be stopped if IsCancellationRequested is set to true for token.

for (int ctr = 0; ctr < Int32.MaxValue; ctr++)
{
    token.ThrowIfCancellationRequested();
    if (ctr % 100000000 == 0)
       Debug.WriteLine(ctr.ToString());
}

Outras dicas

It is likely your console test code that is bugged and your expectations are wrong. In the console application 2t keeps on running too but the program quit before t2 finished.

Cancellation token sources are "Cooperative cancelation" if you want t2 to end early you need to check inside t2 if the cancellation has happened yet.

Task t2 = Task.Run(() =>
{
    Debug.WriteLine(Int32.MaxValue.ToString());
    for (Int32 ctr = 0; ctr < Int32.MaxValue; ctr++)  // 
    {
        if (ctr % 100000000 == 0)
            Debug.WriteLine(ctr.ToString());
        token.ThrowIfCancellationRequested();
    }
    Debug.WriteLine("Task {0} finished.",
                        Task.CurrentId);
});
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top