当前位置: 代码网 > it编程>编程语言>C# > c# Task任务的取消方式

c# Task任务的取消方式

2025年02月14日 C# 我要评论
task任务的取消c# 任务的取消,需要用到cancellationtokensource类,cancellationtoken结构体。注意:cancellationtokensource是class

task任务的取消

c# 任务的取消,需要用到cancellationtokensource类,cancellationtoken结构体。

注意:cancellationtokensource是class类型,而cancellationtoken是struct结构体。

任务内部"监听"cancellationtoken方法

任务的内部在合适的时候不停地调用cancellationtoken的throwifcancellationrequested()方法,这个函数会抛出一个叫做operationcanceledexception的异常,它的实现(微软开源代码)如下:

        public void throwifcancellationrequested()
        {
            if (iscancellationrequested) 
                throwoperationcanceledexception();
        }

下面的列子通过task.run产生了一个任务。task任务的内部正式通过抛出operationcanceledexception异常达到被取消的目的。而任务的外部则是通过调用cancellationtokensource实例的cancel()方法来触发取消的动作的。

下面的例子是一个取消task任务的例子

using system;
using system.threading;
using system.threading.tasks;

class program
{
    static async task main()
    {
        var tokensource2 = new cancellationtokensource();
        cancellationtoken ct = tokensource2.token;
        var tokensource3 = new cancellationtokensource();

        var task = task.run(() =>
        {
            // were we already canceled?
            ct.throwifcancellationrequested();
            
            bool moretodo = true;
            while (moretodo)
            {
                // poll on this property if you have to do
                // other cleanup before throwing.
                // clean up here, then...
                if(ct.iscancellationrequested)
                {
                    ct.throwifcancellationrequested();
                }
            }
        },tokensource2.token); // pass same token to task.run.

        thread.sleep(5000);
        tokensource2.cancel();

        // just continue on this thread, or await with try-catch:
        try
        {
            await task;
        }
        catch (operationcanceledexception e)
        {
            console.writeline($"{nameof(operationcanceledexception)} thrown with message: {e.message}");
            bool eqs = e.cancellationtoken.equals(tokensource3.token);
            system.console.writeline($"equals' result: {eqs}.");
            system.console.writeline($"task's status: {task.status}");
        }
        catch (exception ex)
        {
            system.console.writeline(ex.message);
        }
        finally
        {
            tokensource2.dispose();
        }

        console.readkey();
    }
}
/*
the operation was canceled.
operationcanceledexception thrown with message: the operation was canceled.
equals' result: false.
task's status: canceled
*/

这个例子中我们在task的外部创建了2个cancellationtokensource实例,因为cancellationtokensource类包含一个cancellationtoken类的属性token,这也就意味着例子当中包含了两个cancellationtoken实例。

throwifcancellationrequested()方法会把调用它的cancellationtoken实例也作为参数一起携带抛出。

因此catch块参数e中包含的是tokensource2.token,因此它与tokensource3.token进行相等比较输出一定是false。

又因为task.run()方法中传入的第二个参数也是tokensource2.token,task核心框架内部会比较operationcanceledexception异常中携带的cancellationtoken实例和task.run()方法中传入的cancellationtoken实例,如果两者是一样的,则task的status状态设为canceled,表示成功取消;如果两者不一样,task任务仍然会退出,但是task的status状态设为faulted,表示出错。

如果将第29行改为:

},tokensource3.token); // pass same token to task.run.

则,结果输出如下:

operationcanceledexception thrown with message: the operation was canceled.
equals' result: false.
task's status: faulted

看起来,task任务也被取消了,但是实际上是由于出错而退出。因此,task.run的第二个参数可以用来确保内部实际引发取消异常的cancellationtoken实例和task.run传入的cancellationtoken实例要一致才能成功取消,否则框架会误认为你是误操作而导致退出的。因此,task.run的cancellationtoken参数是为了更加安全。

如果将29行改为不带cancellationtoken参数的重载函数,那么返回的也是一样的faulted结果。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com