Search code examples
c#multithreadingcancellationcancellation-token

Stopping a Thread, ManualResetEvent, volatile boolean or cancellationToken


I have a Thread (STAThread) in a Windows Service, which performs a big amount of work. When the windows service is restarted I want to stop this thread gracefully.

I know of a couple of ways

  • A volatile boolean
  • ManualResetEvent
  • CancellationToken

As far as I have found out Thread.Abort is a no go...

What is the best practice ? The work is perfomed in another class than the one where the thread is started, so it is necessary to either introduce a cancellationToken parameter in a constructor or for example have a volatile variable. But I just can't figure out what is smartest.

Update
Just to clarify a little I have wrapped up a very simple example of what I'm talking about. As said earlier, this is being done in a windows service. Right now I'm thinking a volatile boolean that is checked on in the loop or a cancellationToken.... I cannot wait for the loop to finish, as stated below it can take several minutes, making the system administrators of the server believe that something is wrong with the service when they need to restart it.... I can without problems just drop all the work within the loop without problems, however I cannot do this with a Thread.Abort it is "evil" and furthermore a COM interface is called, so a small clean up is needed.

Class Scheduler{
  private Thread apartmentThread;
  private Worker worker;

  void Scheduling(){
    worker = new Worker();
    apartmentThread = new Thread(Run);
    apartmentThread.SetApartmentState(ApartmentState.STA);
    apartmentThread.Start();    
  }

  private void Run() {
    while (!token.IsCancellationRequested) {
      Thread.Sleep(pollInterval * MillisecondsToSeconds);
      if (!token.IsCancellationRequested) {
        worker.DoWork();
      }
    }
  }
}

Class Worker{
  //This will take several minutes....
  public void DoWork(){
    for(int i = 0; i < 50000; i++){
      //Do some work including communication with a COM interface
      //Communication with COM interface doesn't take long
    }
  }
}

UPDATE
Just examined performance, using a cancellationToken where the isCancelled state is "examined" in the code, is much faster than using a waitOne on a ManualResetEventSlim. Some quick figuers, an if on the cancellationToken iterating 100.000.000 times in a for loop costs me approx. 500 ms, where the WaitOne costs approx. 3 seconds. So performance in this scenario it is faster to use the cancellationToken.


Solution

  • You haven't posted enough of your implementation but I would highly recommend a CancellationToken if that is available to you. It's simple enough to use and understand from a maintainability standpoint. You can setup cooperative cancellation as well too if you decide to have more than one worker thread.

    If you find yourself in a situation where this thread may block for long periods of time, it's best to setup your architecture so that this doesn't occur. You shouldn't be starting threads that won't play nice when you tell them to stop. If they don't stop when you ask them, the only real way is to tear down the process and let the OS kill them.

    Eric Lippert posted a fantastic answer to a somewhat-related question here.