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).