3

What is the most efficient way to create a “cancel” event in a C# program that is crunching a large set of data in a loop on a separate thread?

For now, I am simply using a cancel event that is triggered from my UI thread, which subsequently calls an “onCancel” function on the number crunching thread. That cancel function sets a variable to “true”, which the crunch loop checks periodically, e.g.

Class Cruncher {  
    private bool cancel = false;

    public cruncher()
    {
        crunch();
    }

    private void crunch()  
    {   
        while(conditions AND !cancel) { crunch; }

        dispose_resources;
    }

    private void onCancel() 
    { 
        cancel = true;
    }
}

While I am not checking the cancel variable as often as my example above (and not actually performing a NOT cancel), I would still like to optimize this crunch method as much as possible. Any examples where this is done more efficiently would be very nice to see.

Robotnik
  • 3,643
  • 3
  • 31
  • 49
rnd
  • 95
  • 5
  • 1
    In very tight loops, I've optimized by only checking every 100 or 1000 iterations instead of every one. But you do have to check. – Stephen Cleary Aug 05 '10 at 22:04

5 Answers5

3

The cancel event/flag should be a volatile... I asked a very similar question to yours: Is it safe to use a boolean flag to stop a thread from running in C#

I would also recommend that when you cancel your threads you wait for all of them to cancel by using something similar to the C# version of CountDownLatch. It's useful when you want to guarantee that the thread is canceled.

Community
  • 1
  • 1
Kiril
  • 39,672
  • 31
  • 167
  • 226
1

It will ultimately always result in something like this - although it's important that you make your cancel variable volatile, as otherwise the worker threads may not see the change from the cancelling thread.

You've got to check something periodically unless you want to go the more drastic route of interrupting the thread (which I don't recommend). Checking a single Boolean flag isn't likely to be exactly costly... if you can do a reasonable chunk of work in each iteration of the loop (enough to dwarf the cost of the check) then that's fine.

If you ever need to perform any waiting, however (in the worker thread), then you may be able to improve matters, by using a form of waiting (e.g. Monitor.Wait) which allows the cancelling thread to wake any waiting threads up early. That won't make normal operation more efficient, but it will allow the threads to terminate more quickly in the event of cancellation.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • C# in Depth is currently on a truck heading my way from Amazon. Looking forward to it! – rnd Aug 06 '10 at 00:08
1

Especially since it's UI-triggered, I would recommend just leveraging the BackgroundWorker that's already in the framework, especially since it'll nicely have the progress and done events happen on the UI thread for you (so you don't have to invoke it over yourself).

Then you can just use the CancelAsync() call. Admittedly, it's not much different than what you're already doing, just done in the framework already (and including the thread synchronization logic)

As Jon mentioned, you're still going to want to do cooperative cancellation (checking CancellationPending in your DoWork for use of BackgroundWorker) since the 'interrupt/abort the thread' option is something you want to avoid if possible.

If in .NET 4 you can use TPL and the new Cancellation support, but again it's focused on cooperative cancellation.

James Manning
  • 13,429
  • 2
  • 40
  • 64
  • Thanks for the tips on background worker, James. I will consider moving over to this rather than my own implementation, since my threading system is a temporary test container at the moment. – rnd Aug 06 '10 at 00:01
1

I recommend using the unified cancellation model that was introduced in .NET 4.0 (if .NET 4.0 is an option).

It is very efficient, and allows integrated cancellation with Task objects and Parallel LINQ.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
0

i would do it the same way. i would also add Thread.Sleep in to the loop to yield control to the main thread.

http://msdn.microsoft.com/en-us/library/7a2f3ay4%28VS.80%29.aspx

akonsu
  • 28,824
  • 33
  • 119
  • 194
  • I don't think that Thread.Sleep is necessary when there is a proper signaling implemented (i.e. Monitor or CountDownLatch). – Kiril Aug 05 '10 at 18:57
  • agree, i was talking about a simple variable check inside a loop. – akonsu Aug 05 '10 at 19:08