任务并行库 - 如何使用 TaskContinuationOptions.OnlyOnCanceled 来触发延续?

发布于 2024-09-27 16:47:19 字数 2512 浏览 4 评论 0原文

我正在尝试 .NET 4.0 中的任务支持 - 特别是延续支持。我感到困惑的是,我无法弄清楚如何在设置要执行的 TaskContinuationOptions.OnlyOnCanceled 标志的情况下继续执行。如果我在工作例程中执行 ThrowIfCancellationRequested,它似乎只会作为错误而不是取消操作从延续中传播出来。例如,给定以下代码:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace TaskExp1
{
    class Program
    {
        static void Main()
        {
            var n = 10000;

            DumpThreadId("main method");

            var cts = new CancellationTokenSource();
            var task = Task.Factory.StartNew<int>(_ => Sum(cts.Token, n), 
                                                  cts.Token);

            task.ContinueWith(t =>
            {
                DumpThreadId("ContinueWith Completed, ", newline:false);
                Console.WriteLine("The result is " + t.Result);
            }, TaskContinuationOptions.OnlyOnRanToCompletion);

            task.ContinueWith(t =>
            {
                DumpThreadId("ContinueWith Faulted, ", newline: false);
                Console.WriteLine(t.Exception.InnerExceptions[0].Message);
            }, TaskContinuationOptions.OnlyOnFaulted);

            task.ContinueWith(_ =>
            {
                DumpThreadId("ContinueWith Cancelled, ");
            }, TaskContinuationOptions.OnlyOnCanceled);

            Console.WriteLine("Computing sum of " + n + " ...");
            Thread.SpinWait(100000);
            cts.Cancel();

            Console.WriteLine("Done.");
            Console.ReadLine();
        }

        static int Sum(CancellationToken cancelToken, int n)
        {
            DumpThreadId("from Sum method");
            int sum = 0;
            for (; n > 0; n--)
            {
                Thread.SpinWait(500000);
                if (n == 10000) cancelToken.ThrowIfCancellationRequested();
                checked { sum += n; }
            }
            return sum;
        }

        static void DumpThreadId(string msg = "", bool newline = true)
        {
            var formattedMsg = String.Format("ThreadId: {0} {1}", 
                                  Thread.CurrentThread.ManagedThreadId, msg);
            if (newline) formattedMsg += "\n";
            Console.Write(formattedMsg);
        }
    }
}

此输出:

ThreadId: 9 main method
Computing sum of 10000 ...
Done.
ThreadId: 10 from Sum method
ThreadId: 10 ContinueWith Faulted, The operation was canceled.

如何退出我的工作程序(Sum)方法,以便触发 OnlyOnCanceled 延续?

I'm experimenting with the Task support in .NET 4.0 - specifically with the continuation support. What I'm perplexed about is that I can't figure out how to get a continuation with the TaskContinuationOptions.OnlyOnCanceled flag set to execute. If I do a ThrowIfCancellationRequested in my worker routine, it only seems to propagate out of the continuation as a fault instead of a cancel operation. For instance, given this code:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace TaskExp1
{
    class Program
    {
        static void Main()
        {
            var n = 10000;

            DumpThreadId("main method");

            var cts = new CancellationTokenSource();
            var task = Task.Factory.StartNew<int>(_ => Sum(cts.Token, n), 
                                                  cts.Token);

            task.ContinueWith(t =>
            {
                DumpThreadId("ContinueWith Completed, ", newline:false);
                Console.WriteLine("The result is " + t.Result);
            }, TaskContinuationOptions.OnlyOnRanToCompletion);

            task.ContinueWith(t =>
            {
                DumpThreadId("ContinueWith Faulted, ", newline: false);
                Console.WriteLine(t.Exception.InnerExceptions[0].Message);
            }, TaskContinuationOptions.OnlyOnFaulted);

            task.ContinueWith(_ =>
            {
                DumpThreadId("ContinueWith Cancelled, ");
            }, TaskContinuationOptions.OnlyOnCanceled);

            Console.WriteLine("Computing sum of " + n + " ...");
            Thread.SpinWait(100000);
            cts.Cancel();

            Console.WriteLine("Done.");
            Console.ReadLine();
        }

        static int Sum(CancellationToken cancelToken, int n)
        {
            DumpThreadId("from Sum method");
            int sum = 0;
            for (; n > 0; n--)
            {
                Thread.SpinWait(500000);
                if (n == 10000) cancelToken.ThrowIfCancellationRequested();
                checked { sum += n; }
            }
            return sum;
        }

        static void DumpThreadId(string msg = "", bool newline = true)
        {
            var formattedMsg = String.Format("ThreadId: {0} {1}", 
                                  Thread.CurrentThread.ManagedThreadId, msg);
            if (newline) formattedMsg += "\n";
            Console.Write(formattedMsg);
        }
    }
}

This outputs:

ThreadId: 9 main method
Computing sum of 10000 ...
Done.
ThreadId: 10 from Sum method
ThreadId: 10 ContinueWith Faulted, The operation was canceled.

How do I exit my worker (Sum) method such that the OnlyOnCanceled continuation gets fired?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

听不够的曲调 2024-10-04 16:47:19

当您使用 _ => 时您正在使用

Func<Object, TResult> function, Object state

重载的 lambda 表达式。如果将 Factory.StartNew 更改为

Task.Factory.StartNew<int>(() => Sum(cts.Token, n), cts.Token);

它将调用“ContinueWith Cancelled”。

When you are using the _ => lambda expression you are using the

Func<Object, TResult> function, Object state

overload. If you change the Factory.StartNew to

Task.Factory.StartNew<int>(() => Sum(cts.Token, n), cts.Token);

it will call the "ContinueWith Cancelled".

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文