【问题标题】:Cancel Task running under User Control取消在用户控制下运行的任务
【发布时间】:2019-04-04 10:51:13
【问题描述】:

在我的项目中,导航更改的用户控件很少。其中一个控件运行任务。我是这样做的:

public partial class uc_WorkingArea : UserControl
{
    CancellationTokenSource cts = new CancellationTokenSource();
    CancellationToken token;

    public uc_WorkingArea()
        {
            InitializeComponent();
            this.Unloaded += uc_WorkingArea_Unloaded;
            token = cts.Token;
            Task Printer1 = Task.Run(() => PrinterPooler(lst_PrinterStruct, 0), cts.Token);
        }


         private void uc_WorkingArea_Unloaded(object sender, RoutedEventArgs e)
        {
            cts.Cancel();
            if (token.CanBeCanceled)
            {
                MessageBox.Show("Can be canceled");
            }

            if (token.IsCancellationRequested)
            {
                MessageBox.Show("Canceled requested");
            }
            cts.Cancel();
            MessageBox.Show("Status: " + Printer1.Status.ToString());
        }
}

当我离开当前用户控制并切换到另一个 uc_WorkingArea_Unloaded 时执行。我看到消息,可以取消该任务并接受取消请求。

但是,Printer1 任务的当前状态仍然是“IsRunning”。 所以,如果我返回到这个用户控件,任务会再次启动,并且应用程序有两个正在运行的类似任务。

我试过在Factory下运行任务,像这样

Task Printer1 = Task.Factory.StartNew(() => PrinterPooler(lst_PrinterStruct, 0), cts.Token);

但没有成功。应用仍然运行两个类似的任务。

PrinterPooler 方法不是异步的。

我不明白哪里出错了。需要你们的帮助。

【问题讨论】:

    标签: c# task


    【解决方案1】:

    您必须将令牌传递给PrintPooler 方法,并在里面检查它是否应该被取消。

    for(int i = 0; i < 10000; i++)
    {
       DoStuff();
       cancelToken.ThrowIfCancellationRequested(); // if tasks end with this exception, it knows the work has been cancelled
    }
    

    取消任务不会停止执行,它只会向内部代码发出信号,表明它应该结束,并根据执行停止的方式将任务状态设置为 Cancelled/Faulted/RanToCompletion。

    请注意,您需要将相同的令牌传递给 Task 和将抛出它的方法。

    【讨论】:

    • 是的!这完美地工作。但是,另一个问题。也许你可以回答它。我的任务很少,它们运行相同的函数,但参数不同。我可以为每个任务运行使用相同的 cts 吗?
    • 他们可以共享取消令牌,将被一次性全部取消
    • 不错!非常感谢您的解释。今天你救了我的命:)
    【解决方案2】:

    关于这个帖子How do I abort/cancel TPL Tasks?

    你必须自己实现你的取消条件。例如:

    public partial class uc_WorkingArea : UserControl
    {
        public CancellationTokenSource cts = new CancellationTokenSource();
        public CancellationToken token;
        public Task Printer1;
    
        public uc_WorkingArea()
        {
            token = cts.Token;
            Printer1 = Task.Factory.StartNew(() =>
            {
                while (!token.IsCancellationRequested)
                {
                    Console.WriteLine("run");
                    Application.DoEvents();
                }
            }, token);
        }
    }
    

    取消通话:

        uc_WorkingArea gc = new uc_WorkingArea();
    
        for (int i = 0; i < 10; i++) //PASS SOME TIME
        {
            Application.DoEvents(); //CONSOLE SHOULD SPAM 'RUN' FROM TASK
            Thread.Sleep(1);
        }
    
        gc.cts.Cancel(); //CANCEL CALL, WHILE LOOP END
        if (gc.token.IsCancellationRequested)
        {
            Console.WriteLine("stop");
            MessageBox.Show("Canceled requested");
    
        }
        gc.cts.Dispose();
        gc.Printer1.Dispose();
    

    希望对你有帮助。

    【讨论】:

    • 嗨。谢谢你的答案。我已经有决定了。但是,我会将您的答案放入我的代码草稿簿中。也许我可以稍后应用您的决定。无论如何,谢谢!
    猜你喜欢
    • 2016-01-03
    • 2015-03-11
    • 1970-01-01
    • 2019-07-10
    • 1970-01-01
    • 2010-11-13
    • 1970-01-01
    • 1970-01-01
    • 2012-04-12
    相关资源
    最近更新 更多