正确的方法来处理Windows服务错误

时间:2012-08-20 23:22:28

标签: c# multithreading windows-services threadpool semaphore

我正在构建一个多线程的Windows服务。一旦所有线程都通过,我有点困难找出干净地停止服务的最佳方法。代码如下。我查看了ManualResetEvent,CountdownEvent并使用了Interlocked。我不确定哪一个最适合我的实施。

感谢您的帮助。

    private bool _isExiting;
    private bool IsExiting //if this is set to true exit but wait for all threads
    {
        get { return _isExiting; }
        set
        {
            _isExiting = value;
            if (value)
                Stop();
        }
    }
   private JobProfiler profiler;

   protected override void OnStart(string[] args)
    {
        try
        {
            profiler = new Profiler(MaxThreads);
            ThreadPool.QueueUserWorkItem(DoWork); // main thread set up thread for work
        }
        catch (Exception ex)
        {
            LogError(ex);
            Stop();
        }
    }

    protected void DoWork(object data)
    {
        while (!IsExiting)
        {
            try
            {
                profiler.RunProfiles(profiles); //this should wait until all child threads are done
                Thread.Sleep(ThreadSleep); //sleep before next iteration
            }
            catch (Exception ex)
            {
                LogError(ex);
                errorCount++;

                if (errorCount > 10)  //if 10 serious errors happen stop the service
                {
                    IsExiting = true;
                    break;
                }
            }
        }
    }

    protected override void OnStop()
    {
        try
        {

            if(profiler != null)
                profiler.IsExiting = true; //setting a variable here to signal all remaining threads to stop

            //here it should be waiting for the main and child threads to finish

            base.OnStop();
        }
        catch
        {
            base.OnStop();
        }
    }


    //profiler class
    //******************************************************

    private readonly Semaphore _throttle;   //setting up a throttle for the number of threads we will allow to execute at once

    public void RunProfiles(List<Profiles> profiles)
    {
        foreach (var profile in profiles)
        {
            if (IsExiting) break; //if an exit command is called stop iterating

            _throttle.WaitOne(); // Wait on a semaphore slot to become available
            ThreadPool.QueueUserWorkItem(RunProfile, profile ); //then add to thread queue

        }
    }

    private void RunProfile(object profile)
    {
        try
        {
            var p = (profile as Profile);

            if (p == null || IsExiting)
            {
                _throttle.Release(); // Release the semaphore slot if profile not found or if we're exiting
                return;
            }

            //****
            //do a bunch of stuff
            //****

            _throttle.Release(); // Release the semaphore slot

        }
        catch (Exception ex)
        {
            log.Error(ex);
            _throttle.Release(); // Release the semaphore slot
        }

    }

1 个答案:

答案 0 :(得分:0)

我会使用Tasks(来自.NET 4.0的TPL)并使用CancellationToken取消任务,如果发生Stop事件或某些异常并且您想要停止服务。

但是如果你想坚持使用信号量或较旧的同步原语,你的解决方案就可以正常工作。

另见本文:Threading

有几个有用的例子可以帮助您选择最佳解决方案。我相信CountdownEvent是高度优化的并且与操作系统无关,所以从你的列表中我会选择那个。