6

我在 .Net 3.5 中有一个多线程 Windows 服务,当创建多个线程时,我无法正确停止该服务。

该服务过去只创建一个线程来完成所有工作,而我只是将其更改为多线程。它工作得很好,但是当服务停止时,如果有多个线程正在执行,它会挂起服务,直到所有线程都完成。

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

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

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

        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 方法仅在所有线程完成后执行。

任何线索可以改变什么来解决这个问题?

4

2 回答 2

10

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

I've fielded many multi-threaded Windows Services but I prefer to create my own background threads rather than use the ThreadPool since these are long-running threads. I instantiate worker classes and launch their DoWork() method on the thread. I also prefer to use callbacks to the launching class to check for a stop signal and pass status rather than just test against a global variable.

于 2012-05-17T22:50:00.640 回答
3

您缺少访问 的内存屏障StopService,如果您有多个 CPU,这可能是个问题。更好地锁定所有对共享变量的访问的任何引用对象。例如:

object @lock;

...

lock (@lock)
{
    StopService = true;
}

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

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

于 2012-05-17T22:11:48.990 回答