如何取消异步调用?

时间:2009-11-13 13:57:53

标签: c# .net c#-3.0 asynchronous

如何取消异步通话? .NET APM似乎不支持此操作。

我的代码中有以下循环,它在ThreadPool上生成多个线程。当我单击UI上的按钮时,我希望这些线程(或异步调用)结束。

foreach (var sku in skus)
{
    loadSku.BeginInvoke(...
}

除了创建全局“取消标志”并使用异步方法查找它之外,还有其他优雅的解决方案吗?

3 个答案:

答案 0 :(得分:18)

“取消标志”是这样做的方式,虽然不是全球性的,但必然。不可避免的一点是,您需要某种方式向线程发出信号,告知它应该停止它正在做的事情。

BeginInvoke的情况下,除了全局标志之外,这很难做到,因为工作是在线程池上执行的,而你不知道哪个线程。您有几个选项(按优先顺序排列):

  1. 使用BackgroundWorker代替BeginInvoke。这有cancellation functionality baked-in。这还有其他好处,例如progress monitoring"Work complete" callbacks。它也很好handles exceptions
  2. 使用ThreadPool.QueueUserWorkItem,将对象作为具有Cancel()方法的状态传入,该方法设置执行代码可以检查的Cancelled标志。当然,您需要保留对状态对象的引用,以便可以在其上调用Cancel()(这是BackgroundWorker为您所做的事情 - 您的表单上有一个组件。(感谢Fredrik提醒您注意这一点。)
  3. 创建您自己的ThreadStart委托,与选项2一样传入州对象。

答案 1 :(得分:1)

如果您正在寻找“TerminateAsnyc”方法,则无法找到。因此,不,使用Control.BeginInvoke / EndInvoke时可能没有优雅的方法。因此,我将布尔标志放在UI线程上,让异步执行的委托在执行时定期检查该标志。

但是,您可能会检查使用后台工作线程。

答案 2 :(得分:0)

肯定有其他解决方案,虽然我不知道我会称之为“优雅”。

您可以在线程上调用Abort或Interrupt,但这些可能会产生一些负面影响。就个人而言,如果可能的话,我更喜欢使用BackgroundWorker。它有一个Cancel功能,但它类似于你提到的 - 类中的bool标志,你必须在执行代码中定期检查(至少它不是全局标志)。 This post on stopping threads in .NET有点旧,但是我在上面提到的其他选项中遇到了一些陷阱。