【问题标题】:Cancel/Abort a Task in C#在 C# 中取消/中止任务
【发布时间】:2018-05-08 17:38:53
【问题描述】:

我有一个 C# 程序,它执行一些服务调用。 我需要在这个程序中添加一些代码,以便能够在我单击按钮(winform)时停止这些服务调用[例如,如果调用太长并且用户很无聊]。

困难在于我无法修改执行调用的代码块。

为了做到这一点,我计划使用 Unity 框架进行一些拦截。 每次输入服务调用代码块时,我都想创建一个任务。然后,如果用户单击我的按钮,则取消此任务。

我查看了 CancellationToken 但问题是我不能修改调用块,所以我不能做 if(ct.IsCancellationRequested)ct.ThrowIfCancellationRequested(); AutoResetEvent 和 ManualResetEvent 也是如此。 这些调用并不总是异步的,并且是使用cancellationToken进行的,所以我认为捕获OperationCanceledException是不可能的。

我也研究过使用线程并做了一些Thread.Abort(),但这种方法似乎每次有人调用它都会杀死小狗。

这是我当前程序的示例(尚未实现拦截,我想先在一次调用中测试它):

private void Test()
{
    Task.Factory.StartNew(MyServiceCallFunction); // How to cancel the task when I press a button ?
}

// Can't touch the inside of this function :
private void MyServiceCallFunction()
{
    // Blabla I prepare the datas for the call
    // Blabla I do the call
}

我该怎么做? (我没有义务使用任务)

谢谢,

【问题讨论】:

  • 不要使用Threads,除非你认为你可以比 .NET 框架更好地管理它们
  • @user1274820 你并不关心你造成的所有问题并不意味着它们不存在。 TPL 没有公开中止底层线程的方法,不是因为它试图残忍或疏忽,而是因为用户根本不知道它导致的复杂性以及如何以这种方式设计他们的程序它将在代码中几乎任何地方抛出任意异常的情况下发挥作用。在这种情况下,地球上几乎没有任何程序可以正常运行。
  • @user1274820 所以,如果你站在马路上,一辆汽车向你开过来,你会捂住眼睛,因为你没有注意到的问题不是问题吗?你没有意识到坏事正在发生并不意味着它们没有发生,这只是意味着你实际上解决这些问题的能力要低得多。
  • @wdosanjos 请停止传播错误信息。 Thread.Abort() 不折旧。查一下。

标签: c# multithreading


【解决方案1】:

“正确”的做法是使用 CancellationTokens,但由于您无法修改正在运行的代码,唯一的其他方法是杀死小狗并使用 Thread.Abort()

类似:

Thread t;
Task.Factory.StartNew(() =>
    {
        t = Thread.CurrentThread;
        MyServiceCallFunction();
    });

t.Abort();

【讨论】:

  • ^ 这 - 无论好坏 - 很简单,并且在 99.99% 的时间里都有效。
  • @user1274820 这不是总是错,只是经常错,并建议在不合适的情况下使用它,并且没有适当的指示何时出现这些情况,只是因为它看起来很容易,尽管它可能会给寻求有效解决方案的人带来所有问题和头痛,但它弊大于利。你为帮助人们解决问题而感到如此自豪是......令人沮丧。
  • @Servy 接受“这是不可能的”作为对问题的回答的事实让我感到沮丧。
  • @user1274820 您所说的这表明您不了解代码的实际作用。你认为它解决了问题实际上并没有解决问题,这会让你变得更糟,然后意识到问题实际上并没有解决。另外,我并没有说解决问题是不可能的,只是说这种方法不是可接受的解决方案。
  • @oxidur 接受它或让它保持原样。正如我最初所说,正确的方法是使用取消令牌,但既然你说你不能,看看这是否适合你。公平警告:彻底测试并自行承担使用风险。正如您所说,此解决方案类似于杀死小狗,但可能适用于您的情况。
【解决方案2】:

非常有趣的问题。当然,当第三方调用在做 TPL 时,你什么也做不了;在您的情况下,它是 MyServiceCallFunction()。

我也遇到过类似的情况,这篇博文对我有帮助:https://social.msdn.microsoft.com/Forums/vstudio/en-US/d0bcb415-fb1e-42e4-90f8-c43a088537fb/aborting-a-long-running-task-in-tpl?forum=parallelextensions

(阅读:Stephen Toub - MSFTMicrosoft (MSFT) cmets)

他提到了这个解决方案:

int Test(CancellationToken token)
    {
        Thread currentThread = Thread.CurrentThread;
        using (token.Register(currentThread.Abort))
        {
            MyServiceCallFunction()
        }
    }

还将 Task.Factory.StartNew (...) 替换为 Task.Run(...) ;同样,infect 后者更强,但可读性更好。

【讨论】:

  • 也使用Thread.Abort(),但将其与CancellationToken 链接起来,这样看起来“更正确”。我想知道社区将如何接受这个回复。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-15
  • 2019-01-06
相关资源
最近更新 更多