18

How to cancel an asynchronous call? The .NET APM doesn't seem to support this operation.

I have the following loop in my code which spawns multiple threads on the ThreadPool. When I click a button on my UI, I would like these threads (or asynchronous calls) to end.

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

Is there any elegant solution other than creating a global "Cancel flag" and having the asynchronous methods to look for it?

Kate Gregory
  • 18,808
  • 8
  • 56
  • 85
Martin
  • 39,309
  • 62
  • 192
  • 278

3 Answers3

19

A "cancel flag" is the way to do it, though not a global one, necessarily. The unavoidable point is that you need some way to signal to the thread that it should stop what it's doing.

In the case of BeginInvoke, this is hard to do with anything but a global flag, because the work is carried out on the threadpool, and you don't know which thread. You have a couple of options (in order of preference):

  1. Use the BackgroundWorker instead of BeginInvoke. This has cancellation functionality baked-in. This has other benefits, like progress monitoring, and "Work complete" callbacks. It also nicely handles exceptions.
  2. Use ThreadPool.QueueUserWorkItem, passing in an object as the state that has a Cancel() method that sets a Cancelled flag that the executing code can check. Of course you'll need to keep a reference to the state object so you can call Cancel() on it (which is something the BackgroundWorker does for you - you have a component on your form. (Thanks to Fredrik for reminding about this).
  3. Create your own ThreadStart delegate, passing in a state object as with option 2.
Community
  • 1
  • 1
Neil Barnwell
  • 41,080
  • 29
  • 148
  • 220
  • +1 - As an addition; the `WaitCallback` used with the `ThreadPool.QueueUserWorkItem` takes a state object parameter, so that can also be used, instead of creating custom ThreadStart delegates. – Fredrik Mörk Nov 13 '09 at 14:06
  • Ahh yes - I will plagarise your QueueUserWorkItem point. It's largely the same, but I have to admit I **always** use TP.QUWI rather than managing threads myself. – Neil Barnwell Nov 13 '09 at 14:08
  • +1: and on the topic of QUWI, it's also much more lightweight as there is(/may be) no need to create the thread if the pool isn't full. – Steven Evers Nov 13 '09 at 17:40
  • -1 for not referencing someone answer you copied word by word. And thumbs up for more clearer and additional information. http://social.msdn.microsoft.com/Forums/en-US/4de6dd12-cf9b-427b-bd30-7a26c3e86bc2/how-to-cancel-asynchronous-method-execution?forum=netfxbcl – electricalbah Mar 06 '14 at 02:40
  • 1
    @electricalbah Check the dates. This post is the original from 2009, not the MSDN article from 2012 that you referenced. It is *they* who should reference *me* in this case. But it's the internet so there's no point worrying about it. Shame you downvoted without checking the facts, though. – Neil Barnwell Mar 06 '14 at 21:58
  • @NeilBarnwell I see, sorry about that. I did check the dates but mistook the day for the year. I will compensate for my foolishness. – electricalbah Mar 07 '14 at 00:22
  • 1
    @electricalbah A simple mistake. I'm surprised that I was quoted, but not verbatim. Someone took the time to carve bits of my post and write their own with that content. Strange phenomenon. – Neil Barnwell Mar 08 '14 at 22:24
1

If you're lookin for a "TerminateAsnyc" method, you won't find one. Therefore, no, there's probably no elegant way while using Control.BeginInvoke/EndInvoke. Thus, I'd put the boolean flag on the UI thread and have the delegate being executed asynchronously check that flag periodically while it's executing.

However, you might check into using background worker threads.

Travis Heseman
  • 11,359
  • 8
  • 37
  • 46
0

There are definitely other solutions, although I don't know that I would call them "elegant".

you could call Abort or Interrupt on the thread but these can have some negative side effects. Personally, for something like this I prefer to use BackgroundWorker if possible. It has a Cancel feature but it is similar to what you mentioned - a bool flag in the class that you have to periodically check for in the executing code (at least it's not a global flag). This post on stopping threads in .NET is a bit old but goes over some of the pitfalls of the other options I mentioned above.

Ryan Elkins
  • 5,731
  • 13
  • 41
  • 67