0

我正在构建一个多线程 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
        }

    }
4

1 回答 1

0

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

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

另请查看这篇文章:线程

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

于 2012-08-21T00:48:08.480 回答