停止线程,ManualResetEvent,易失性布尔值或CancellationToken [英] Stopping a Thread, ManualResetEvent, volatile boolean or cancellationToken

查看:122
本文介绍了停止线程,ManualResetEvent,易失性布尔值或CancellationToken的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Windows Service中有一个线程(STAThread),它执行大量工作.重新启动Windows服务后,我要正常停止该线程.

我知道几种方法

  • 易失的布尔值
  • ManualResetEvent
  • CancellationToken

据我所知Thread.Abort是不行的...

最佳做法是什么? 工作是在不同于启动线程的类中进行的,因此有必要在构造函数中引入CancellationToken参数,或者例如具有volatile变量.但我只是不知道什么是最聪明的.

更新
为了澄清一点,我总结了一个非常简单的示例.如前所述,这是在Windows服务中完成的.现在,我正在考虑在循环中或CancellationToken中检查的易失性布尔值.... 我不能等待循环完成,如下所述,这可能需要几分钟,这使得服务器的系统管理员在需要重新启动服务时认为服务出了点问题....我可以毫无问题地将所有内容全部删除循环中的工作没有问题,但是我无法使用Thread.Abort,它是邪恶的",而且还调用了COM接口,因此需要进行少量清理.

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
    }
  }
}

更新
刚检查过的性能,使用在代码中检查"了isCancelled状态的cancelationToken,比在ManualResetEventSlim上使用waitOne快得多.一些快速的角色,如果在cancelToken上的if在for循环中迭代100.000.000次,则大约需要花费我约20%的费用. 500毫秒,其中WaitOne的成本约为3秒因此,在这种情况下,使用cancelageToken的性能会更快.

解决方案

您尚未发布足够的实现,但是我强烈建议您使用CancellationToken.从可维护性的角度来看,它非常易于使用和理解.如果您决定拥有多个工作线程,则也可以设置协作取消.

如果您发现该线程可能长时间阻塞,则最好设置您的体系结构,以免发生这种情况.当您告诉它们停止时,您不应该启动不会发挥良好作用的线程.如果您问他们时还没有停止,唯一真正的方法就是拆除进程并让OS杀死它们.

埃里克·利珀特(Eric Lippert)在此处发布了一个很棒的答案.

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.

解决方案

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.

这篇关于停止线程,ManualResetEvent,易失性布尔值或CancellationToken的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆