views:

989

answers:

9

I have a loop running that will process 1000's of records, currently once the loop is running it can't be stopped and the user must wait until it is finished. How can I stop the loop when someone clicks a 'Cancel' button? How do I break into that other routine?

Thanks

+14  A: 

You can run it in its own thread and abort the thread. Just beware that that might leave the operation in a bad state.

Instead, you should create an exit flag that the thread checks at safepoints. If it's marked for exiting, the thread will stop as soon as it's safe for it to do so.

Mark S. Rasmussen
I love this idea, the idea of an exit flag is appealing, though the users might complain if there is any sort of delay in reaching it, hopefully it wouldn't be that large of a process ;)
thismat
Will need to check them win msg queue too, DoEvents style, to get the Cancel msg.
rob_g
It would at most take 99% of the time that it takes to process a single record, right? If that is taking a long time you may have other issues.
Ed Swangren
Handle the delay with immediate feedback once they click 'Cancel' and spin a graphic or pump up a progress bar or something to kill the short amount of time until the actual cancel happens. The "perception" of immediate response will usually be good enough!
Doug L.
+1 but perhaps it is worth swapping the order of the two options? The risk of creating bad state by aborting the thread for me makes it the definite second choice.
David Hall
@David Hall I agree. I rephrased and emphasized the second option to make it clear that's the better choice.
Mark S. Rasmussen
A: 

As Mark said you need to implement some kind of co-operative synchronization. People often gravitate to wanting to use Thread.Abort here ... but that is a bad idea.

There are a number of questions that address this, for example see: "Is there a good method in C# for throwing an exception on a given thread."

Rob Walker
+12  A: 

You can just use the BackgroundWorker component.

It's event-based and is very easy to utilize. Looks very appropriate for what you are describing.

It has nice support for cancellation signaling as well as progress reporting too.

And a lot of code examples you can lookup on google.


Set the WorkerSupportsCancellation property so it is true.

backgroundworker1.WorkerSupportsCancellation = true;

Do it before you start the worker.

Then, in the loop, you can poll the CancellationPending property:

if (backgroundWorker1.CancellationPending) return;

Just an example, but you should get the idea.

chakrit
As described in separate answers, you have to set the WorkerSupportsCancellation property to true before you call RunWorkerAsynch(). Your worker code still has to check the flag while looping.
Don Kirkby
I already edited that in.. thanks!
chakrit
A: 

You can add a cancel button which sets a boolean flag

Inside the loop add "Application.DoEvents" at key points and then check the boolean flag. If the flag has been tripped, preform your cleanup and exit the loop.

Maudite
A: 

Hi all, thanks for the replies. It is a backgroundworker but when I use backgroundworker1.cancelAsync(); I get the exception:

"This BackgroundWorker states that it doesn't support cancellation. Modify WorkerSupportsCancellation to state that it does support cancellation"

How do I go about altering this? This is inherited code, sorry!

A: 

Set the WorkerSupportsCancellation property on your BackgroundWorker to true :-)

You've also got to check the CancellationPending property inside your loop to see if you should be aborting processing. The MSDN article that chakrit linked has a nice block of sample code

Edit: D'oh, you got me by a few seconds there chakrit :)

Dan F
A: 

I now have

        backgroundWorker1.WorkerSupportsCancellation = true;
        backgroundWorker1.CancelAsync();

but this doesn't stop the loop, I guess I have the 'WorkerSupportsCancellation' in the wrong place.

Thanks

A: 

"Do it before you start the worker." Thanks!

A: 

Working fine when I added

if (backgroundWorker1.CancellationPending) return;

into the loop.

Many thanks all.

This is not a response to the question. Should be removed.
yeyeyerman