停止multithreadingWindows服务

我在.Net 3.5中有一个multithreading的Windows服务,当创建多个线程时,我有一些麻烦来正确停止服务。

这项服务用于创建一个线程来完成所有工作,我只是将其更改为multithreading。 它工作正常,但是当服务停止时,如果正在执行多个线程,它将挂起服务直到所有线程都完成。

当服务启动时,我创建一个后台线程来处理主进程:

protected override void OnStart(string[] args) { try { //Global variable that is checked by threads to learn if service was stopped DeliveryConstant.StopService = false; bool SetMaxThreadsResult = ThreadPool.SetMaxThreads(10, 10); ThreadStart st = new ThreadStart(StartThreadPool); workerThread = new Thread(st); workerThread.IsBackground = true; serviceStarted = true; workerThread.Start(); } catch (Exception ex) { //Log something; } 

这是StartThreadPool方法:

  //Tried with and without this attribute with no success... [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)] public void StartThreadPool() { while (serviceStarted) { ProcessInfo input = new ProcessInfo(); try { int? NumPendingRequests = GetItems(50, (Guid?)input.ProcessID); if (NumPendingRequests > 0) { input.ProcessType = 1; input.ProcessID = Guid.NewGuid(); ThreadPool.QueueUserWorkItem(new WaitCallback(new DispatchManager().ProcessRequestList), input); } } catch (Exception ex) { //Some Logging here } } DeliveryConstant.StopService = true; } 

我在一个单独的类中创建了一个静态变量,以通知线程服务已停止。 当此变量的值为true时,所有线程都应该停止主循环(每个循环的a):

  public static bool StopService; 

最后,OnStop方法:

 protected override void OnStop() { DeliveryConstant.StopService = true; //flag to tell the worker process to stop serviceStarted = false; workerThread.Join(TimeSpan.FromSeconds(30)); } 

在ProcessRequestList方法中,在每个foreach的末尾,我检查StopService变量的值。 如果是真的,我打破了循环。

这是问题:线程是以50个项目的块创建的。 当我在数据库中有50个或更少的项目时,只创建一个线程,一切都很好。 当我有超过50个项目时,将创建多个线程,当我尝试停止服务时,它不会停止,直到所有后台线程都完成。

从日志中,我可以看到OnStop方法仅在所有线程完成后执行。

有什么可以修改的线索吗?

这个博客的回答说,在所有ThreadPool任务完成之前不会调用OnStop,这对我来说是个新闻,但可以解释你的问题。

我已经部署了许多multithreadingWindows服务,但我更喜欢创建自己的后台线程,而不是使用ThreadPool,因为这些是长时间运行的线程。 我实例化工作类并在线程上启动它们的DoWork()方法。 我也更喜欢使用回调来启动类来检查停止信号并传递状态,而不是仅仅针对全局变量进行测试。

您在访问StopService遇到了内存障碍,如果您有多个CPU,这可能会出现问题。 更好地锁定任何引用对象以进行共享变量的所有访问。 例如:

 object @lock; ... lock (@lock) { StopService = true; } 

编辑 :正如另一个答案所揭示的, 这个问题不是一个锁定问题 ,但我在这里留下这个答案作为检查multithreading同步方案的事情。

使共享变量volatile也可以在许多情况下工作,但certificate正确是更复杂的,因为它不会发出完整的栅栏。