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
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).
A CancellationToken enables cooperative cancellation between threads, thread pool work items, or Task objects. You create a cancellation token by instantiating a CancellationTokenSource object, which manages cancellation tokens retrieved from its CancellationTokenSource. Token property.
CancellationTokenSource - This is the object responsible for creating a cancellation token and sending a cancellation request to all copies of that token. CancellationToken - This is the structure used by listeners to monitor the token's current state.
CancellationTokens for Advanced EventsThey are thread-safe out of the box.
A CancellationToken can only be created by creating a new instance of CancellationTokenSource . CancellationToken is immutable and must be canceled by calling CancellationTokenSource. cancel() on the CancellationTokenSource that creates it. It can only be canceled once.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With