Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Techniques for exiting / cancelling while loops across threads: bool, ManualResetEvent or CancellationToken

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

  1. Are there any pros and cons for each?
  2. Are there cases when you would use one and not another?
  3. 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).

like image 824
Anders Avatar asked Dec 09 '14 23:12

Anders


People also ask

What does a CancellationToken do?

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.

What is difference between CancellationTokenSource and CancellationToken?

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.

Is CancellationToken thread safe?

CancellationTokens for Advanced EventsThey are thread-safe out of the box.

How do I manually cancel a CancellationToken?

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.


1 Answers

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.

like image 138
Keith Nicholas Avatar answered Sep 16 '22 22:09

Keith Nicholas