6

.Net 3.5 でマルチスレッド Windows サービスを使用していますが、複数のスレッドが作成されたときにサービスを適切に停止するのに問題があります。

このサービスは、すべての作業を行うためにスレッドを 1 つだけ作成していましたが、私はこれをマルチスレッドに変更しました。完全に機能しますが、サービスが停止したときに複数のスレッドが実行されている場合、すべてのスレッドが完了するまでサービスがハングします。

サービスが開始されたら、メイン プロセスを処理するバックグラウンド スレッドを作成します。

    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 の場合、すべてのスレッドがメイン ループを停止する必要があります (for each ループ)。

        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 変数の値をチェックします。true の場合、ループを中断します。

問題は次のとおりです。スレッドは 50 項目のチャンクで作成されます。データベースに 50 個以下のアイテムがある場合、スレッドが 1 つだけ作成され、すべてがうまく機能します。アイテムが 50 を超えると複数のスレッドが作成され、サービスを停止しようとすると、すべてのバックグラウンド スレッドが完了するまでサービスが停止しません。

ログから、メソッド OnStop は、すべてのスレッドが完了した後にのみ実行されることがわかります。

それを修正するために何を変更できるかの手がかりはありますか?

4

2 に答える 2

10

This blog answerは、すべての ThreadPool タスクが完了するまで OnStop が呼び出されないと述べています。これは私にとってはニュースですが、問題を説明します。

私は多くのマルチスレッド Windows サービスに対応してきましたが、ThreadPool を使用するよりも独自のバックグラウンド スレッドを作成する方が好きです。これらは実行時間の長いスレッドだからです。ワーカー クラスをインスタンス化し、スレッドで DoWork() メソッドを起動します。また、単にグローバル変数に対してテストするのではなく、起動クラスへのコールバックを使用して停止シグナルをチェックし、ステータスを渡すことも好みます。

于 2012-05-17T22:50:00.640 に答える
3

へのアクセスに関するメモリバリアが欠落しStopServiceています。これは、複数のCPUを使用している場合に問題になる可能性があります。共有変数へのすべてのアクセスに対して、参照オブジェクトをロックすることをお勧めします。例えば:

object @lock;

...

lock (@lock)
{
    StopService = true;
}

編集:別の回答が明らかにしたように、この問題はロックの問題ではありませんでしたが、マルチスレッド同期スキームで確認するために、この回答をここに残しておきます。

共有変数を揮発性にすることも多くの場合に機能しますが、完全なフェンスを放出しないため、正しいことを証明するのはより複雑です。

于 2012-05-17T22:11:48.990 に答える