I am writing a program that has a few threads, each with a while loop that runs until the user specifies it should stop. I thought of a few ways to exit out of the loops, and subsequently the threads, and have outlined these approaches below.
Questions
- Are there any pros and cons for each?
- Are there cases when you would use one and not another?
- I have a heard a few people say they prefer CancellationTokens for exiting threads. What is so appealing with that approach over the other two?
Below follows the approaches.
The bool
Approach
Initially, I had declared a bool and just stated that the loops run until the the user sets the bool to false: while(running) { Thread.Sleep(10); /*do work*/ }
. I then pondered if that is entirely thread-safe. What if the compiler did some optimization and moved the bool to a register. In that case, the threads would see different values for the bool. As a result, I marked the bool with the volatile
keyword to avoid compiler optimizations.
The ManualResetEvent
Approach
My next approach was to create a ManualResetEvent
, and just say that the bool runs while WaitOne() is false: while(!mre.WaitOne(10)) {/*do work*/}
. This will block for 10ms, then run the loop, over and over until we do mre.Set()
and the loop exits.
The CancellationToken
Approach
This approach I have not actually tried yet, but I read several places that people prefer cancelling threads this way. It is apparently thread-safe. One would define a CancellationTokenSource
, call it cts
, then pass cts.Token
to the method run by the new thread and use an if statement to check if cancel has been requested: while(!token.IsCancellationRequested) { Thread.Sleep(10); /*do work*/ }
UPDATE 1:
I found a similar post that concludes that the MRE
approach is significantly slower than the CancellationToken
approach. For full info, see here: Stopping a Thread, ManualResetEvent, volatile boolean or cancellationToken
UPDATE 2:
When it comes to comparing the bool
approach to the other two, Eric Lippert has a good answer here: AutoResetEvent vs. boolean to stop a thread
UPDATE 3:
I found another relevant piece of information. CancellationTokens cannot be reset once cancelled. So it is not ideal for when you just want to cancel out of a loop temporarily, to start it again later. For that, MRE might be better (as you can Set and Reset, to your heart's content).
Most often your threads don't run in tight loops eating all your CPU cycles, often you are waiting for events of some sort, when you wait you can't really wait on a bool. You could have a timeout on your event, wait for the timeout, check the bool, then go back to waiting. This makes for nasty code and also means your thread won't quit till timeouts occur, or you keep you eat your CPU checking a bool.
Reset Event is ok, you can certainly work with it, But CancelellationToken works nicely and is precisely designed for this.