【问题标题】:Cancellation of a Task without Providing the Task method with the CancellationTokenSource取消任务而不向 Task 方法提供 CancellationTokenSource
【发布时间】:2011-06-01 13:14:44
【问题描述】:

我正在尝试提供一种具有两种方法的功能,一种称为 StartTask(action mymethod) 另一个叫 StopTask();

问题是操作必须有权访问 CancellationTokenSource 以检查取消并退出方法(返回),这不是我真正想要的方法可能在另一个组件或层中,我无法推送每个方法来访问到那个取消令牌源,

我无法推送具有检查取消和返回的流程方法的组件的设计者/开发者。

有什么办法可以有这样的东西,我知道这听起来很奇怪而且不适用,只是想问问。

这是我得到的最好的:

       CancellationTokenSource cancellationTokenSource;
    private void button1_Click(object sender, EventArgs e)
    {
        cancellationTokenSource = new CancellationTokenSource();
        Task t = new Task(() => Dowork(CancellationAction), cancellationTokenSource.Token, TaskCreationOptions.LongRunning);
        t.Start();
    }
    private bool CancellationAction()
    {

        if (cancellationTokenSource.IsCancellationRequested)
        {
            label1.Invoke(new MethodInvoker(() =>
                                                {
                                                    label1.Text = "Cancellation Requested!";
                                                }));
            return true;
        }
        return false;
    }
    private void Dowork(Func<bool> Return)
    {
        int x = 1;
        while (true)
        {
            x++;
            label1.Invoke(new MethodInvoker(() =>
                                                {
                                                    label1.Text = x.ToString();
                                                }));
            Thread.Sleep(1000);
            if (Return())
            {
                return;
            }
        }
    }

问题是 DoWork 现在必须有一个参数 func ,但是如果该方法已经接受了其他参数怎么办?任务的创建将在另一个类中,它可能不知道要在 CancellationAction 旁边传递什么参数

【问题讨论】:

  • 正如名称CancellationTokenSource 所暗示的那样,它是CancellationToken来源,获得了我访问Token 属性的权限。通常,该模式是将CancellationToken 传递给相关任务。话虽如此,我无法弄清楚您的最终代码示例要实现的目标。

标签: c# multithreading parallel-processing


【解决方案1】:

如果组件没有提供取消其中一个正在运行的任务的方法,那么调用者应该无法取消它。它可能会使应用程序/数据库/任何东西处于未知状态。

所以基本上较低级别的组件应该为调用者提供一种取消任务的方法(ManualResetEvent、CancelAsync 方法,如 BackgroundWorker 等)。否则调用者应该等待它完成。

如果较低级别的组件不提供这样的功能,则大部分时间都被认为是糟糕的设计。

【讨论】:

    【解决方案2】:

    我不确定我是否完全理解你的问题,但我会试一试。似乎您正在尝试在这里一次解决两个问题。

    首先,您尝试将参数传递给异步线程和/或取消该线程(非常相似的问题)。正如其他人所说,BackgroundWorker 已经处理取消。该实现类似于将任何参数传递给您的线程。例如,如果我要复制该功能,我会向我的工作线程添加一个 Cancel 属性或方法,任何其他组件都可以调用它并检查我的主线程循环中的支持值。现在没有理由取消线程,这只是将值传递和使用工作线程的示例。

    看起来您需要解决的另一个问题是如何在应用程序的不同部分之间发送消息,否则这些部分不需要相互引用。通常,我已经看到通过某种服务提供商完成此操作。在所有组件接收实例或易于访问的上下文或公共模型上实现接口。接口应包含任何事件、方法和属性,以便不同的组件可以通信。

    例如(可能是一个不好的例子,但是......)如果我的语法检查例程应该在文档关闭时取消,我会在 IDocumentService 接口上定义一个 DocumentClosing 事件和 OnDocumentClosing 方法,并在适当的上下文/模型中实现该接口。在创建我的文档查看器 UI 组件和语法检查器线程组件时,我会注入一个类型为接口的上下文/模型的实例。当文档查看器开始关闭文档时,它会从接口调用 OnDocumentClosing 方法。创建线程时,它将附加到 DocumentClosing 事件,并且如果该事件触发,则设置一个标志。然后每隔一段时间检查语法,我会检查标志并酌情取消。

    这种实现使您可以灵活地让任何组件触发适当的事件,并且任何其他组件对它们做出反应,而不管这些组件在您的应用程序中的哪个位置使用。事实上,这种方法即使在同步情况下也很有用,例如菜单项响应应用程序事件而改变状态。它允许对所有组件进行简单的单元测试。而且责任分离意味着您可以根据需要轻松更改任何触发点和响应。

    【讨论】:

      【解决方案3】:

      为什么不使用 BackgroundWorkerThread 或其他线程机制? 使用任务并行库有什么特别的原因吗?

      BackgroundWorkerThread 会给你一个更改取消任务,然后响应取消。

      【讨论】:

      • 使用并行计算有很多优点。
      • 优点太多了,这里就不一一列举了……看看吧。这就像从拨号调制解调器到宽带一样。一旦你这样做了,你就再也回不去了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-31
      • 1970-01-01
      • 1970-01-01
      • 2016-03-11
      • 1970-01-01
      相关资源
      最近更新 更多