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

Tasks (.NET 4.0 の TPL) を使用し、CancellationToken を使用して、Stop イベントまたは何らかの例外が発生し、サービスを停止する場合にタスクをキャンセルします。

しかし、セマフォまたは古い同期プリミティブに固執したい場合、ソリューションは問題なく機能します。

こちらの記事もご覧ください:スレッド化

最適なソリューションを選択するのに役立ついくつかの有用な例があります。CountdownEvent は高度に最適化されており、OS に依存しないと思うので、あなたのリストからそれを選びます。

于 2012-08-21T00:48:08.480 に答える