如何正确停止多线程.NET Windows服务? [英] How to properly stop a multi-threaded .NET windows service?

查看:275
本文介绍了如何正确停止多线程.NET Windows服务?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用C#编写的Windows服务,该服务会创建大量的线程并建立许多网络连接(WMI,SNMP,简单TCP,http)。当尝试使用服务MSC管理单元停止Windows服务时,停止服务的调用返回的速度相对较快,但该过程继续运行了大约30秒钟左右。

I have a windows service written in C# that creates a truck load of threads and makes many network connections (WMI, SNMP, simple TCP, http). When attempting to stop the windows service using the Services MSC snap-in, the call to stop the service returns relatively quickly but the process continues to run for about 30 seconds or so.

主要问题是,可能需要30秒钟以上的时间才能停止。我可以寻找什么,以及如何寻找它?

The primary question is what could be the reason that it is taking 30+ seconds to stop. What can I look for and how do I go about looking for it?

第二个问题是为什么即使进程仍在运行。有没有办法让它仅在进程实际上被终止时才返回?

The secondary question is why is the service msc snap-in (service controller) returning even though the process is still running. Is there a way to get it to only return when the process is actually killed?

以下是该服务的OnStop方法中的代码

Here is the code in the OnStop method of the service

protected override void OnStop()
{
   //doing some tracing
   //......

   //doing some minor single threaded cleanup here
   //......

   base.OnStop();

   //doing some tracing here
}

编辑以响应线程清除答案

你们中的许多人回答说,我应该跟踪所有线程,然后清理它们。我认为这不是一种实用的方法。首先,我无法访问一个位置的所有托管线程。该软件非常庞大,具有不同的组件,项目,甚至可能都是创建线程的第三方dll。我无法在一个位置跟踪所有线程,也无法拥有所有线程检查的标志(即使我可以让所有线程检查标志,许多线程也阻塞了信号量之类的东西。当它们阻塞时,它们可以不要检查。我必须让它们等待超时,然后检查此全局标志,然后再次等待)。

Many of you have answered that I should keep track of all my threads and then clean them up. I don't think that is a practical approach. Firstly, i don't have access to all managed threads in one location. The software is pretty big with different components, projects and even 3rd party dlls that could all be creating threads. There is no way I can keep track of all of them in one location or have a flag that all threads check (even if i could have all threads check a flag, many threads are blocking on things like semaphores. When they are blocking they can't check. I will have to make them wait with a timeout, then check this global flag and the wait again).

IsBackround标志值得检查。再说一次,如何确定是否有任何运行arround的forground线程?我将必须检查创建线程的代码的每个部分。还有什么其他方法,也许是可以帮助我找出答案的工具。

The IsBackround flag is an interesting thing to check. Again though, how can I find out if I have any forground threads running arround? I will have to check every section of the code that creates a thread. Is there any other way, maybe a tool that can help me find this out.

尽管如此,该过程确实停止了。看来我只需要等待一些事情。但是,如果我在OnStop方法中等待X的时间,则该过程大约需要30秒+ X才能停止。无论我尝试做什么,似乎OnStop返回之后该过程大约需要30秒(它并不总是30秒,它可能会有所不同),以使该过程真正停止。

Ultimately though, the process does stop. It would only seem that i need to wait for something. However, if i wait in the OnStop method for X ammount of time, then it takes the process approximately 30 seconds + X to stop. No matter what i try to do, it seems that the process needs approximately 30 seconds (its not always 30 seconds, it can vary) after the OnStop returns for the process to actually stop.

推荐答案

一旦您的 OnStop()回调返回,停止服务的调用就会返回。根据显示的内容,您的 OnStop()方法没有做太多事情,这说明了为什么返回速度如此之快。

The call to stop the service returns as soon as your OnStop() callback returns. Based on what you've shown, your OnStop() method doesn't do much, which explains why it returns so fast.

有两种方法可以导致您的服务退出。

There are a couple of ways to cause your service to exit.

首先,您可以重新制作 OnStop()方法向所有线程发出关闭信号,并等待它们关闭后再退出。正如@DSO建议的那样,您可以使用全局布尔标志来执行此操作(确保将其标记为 volatile )。我通常使用ManualResetEvent,但两者都可以。发信号通知线程退出。然后以某种超时时间加入线程(我通常使用3000毫秒)。如果届时线程仍未退出,则可以调用 Abort()方法退出它们。通常, Abort()方法不被接受,但是考虑到您的进程仍在退出,这没什么大不了的。如果您始终有一个必须中止的线程,则可以对该线程进行重新处理以更响应您的关闭信号。

First, you can rework the OnStop() method to signal all the threads to close and wait for them to close before exiting. As @DSO suggested, you could use a global bool flag to do this (make sure to mark it as volatile). I generally use a ManualResetEvent, but either would work. Signal the threads to exit. Then join the threads with some kind of timeout period (I usually use 3000 milliseconds). If the threads still haven't exited by then, you can call the Abort() method to exit them. Generally, Abort() method is frowned upon, but given that your process is exiting anyway, it's not a big deal. If you consistently have a thread that has to be aborted, you can rework that thread to be more responsive to your shutdown signal.

第二,将您的线程标记为背景线程(请参见此处以获取更多详细信息)。听起来好像您正在对线程使用System.Threading.Thread类,这些类默认情况下是前台线程。这样做将确保线程不会阻止进程退出。如果仅执行托管代码,这将很好地工作。如果您有一个正在等待非托管代码的线程,则不确定设置IsBackground属性是否仍会导致该线程在关机时自动退出,即,您可能仍需要重新设计线程模型以使该线程响应您的响应。关闭请求。

Second, mark your threads as background threads (see here for more details). It sounds like you are using the System.Threading.Thread class for threads, which are foreground threads by default. Doing this will make sure that the threads do not hold up the process from exiting. This will work fine if you are executing managed code only. If you have a thread that is waiting on unmanaged code, I'm not sure if setting the IsBackground property will still cause the thread to exit automatically on shutdown, i.e., you may still have rework your threading model to make this thread respond to your shutdown request.

这篇关于如何正确停止多线程.NET Windows服务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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