0

Windows サービスとして実行されるプログラムを C# で作成しました。アプリケーションは起動して正常に動作しますが、管理コンソールを使用してサービスを停止すると、OnStop 関数が呼び出されません。

OnStart メソッドはメイン プログラムのバックグラウンド スレッドを開始し、そのバックグラウンド スレッドは別のスレッドと ThreadPool を開始して、そのスレッドのために作業を行います。

OnStop 処理を停止する必要があるかどうかを確認するために、他のすべてのスレッドがチェックするブール値フラグを設定しました。スレッドはすべて終了し、プログラムは終了します。

これが私のOnStartのコードです

protected override void OnStart(string[] args)
    {
        base.OnStart(args);
        mainProgram.IsBackground = true;
        mainProgram.Start();
    }

そのコードは機能します。以下は、OnStop のコードです。私が知る限り、呼び出されることはありません。

protected override void OnStop()
    {

        Log.LogMessage("Caught shutdown signal from the OS", "debug");
        base.OnStop();
        shutdown = true;
        mainProgram.Join(15000);
        if (mainProgram.IsAlive) mainProgram.Abort();
    }

そのログ メッセージがログ ファイルに書き込まれることはありません。

どんな助けでも大歓迎です。どこから探し始めればいいのかもわかりません。ありがとう。

EDIT バックグラウンドスレッドをロックしていた問題を解決しました。そのログ ステートメントもコメントアウトしたので、ログ ステートメントが問題の原因ではないことがわかりました。

ブール値フラグに加えて、ManualResetEvent を追加しました。OnStop は次のようになります。

protected override void OnStop()
    {
        System.Diagnostics.Debugger.Break();
        //Log.LogMessage("Caught shutdown signal from the OS", "debug");
        base.OnStop();
        shutdown = true;
        ShutdownX.Set();  //this is the ManualResetEvent
        mainProgram.Join(15000);
        if (mainProgram.IsAlive) mainProgram.Abort();
    }

コードを停止する場所は、mainProgram.RunAgent() 関数 (独自のスレッド) にあります。 while (!shutdown) {

                SqlCommand DbCommand = dbConnection.CreateCommand();
                DbCommand.CommandText = "SELECT id, SourceID, CastingSN, Result FROM db_owner.queue";

                SqlDataReader DbReader = null;
                try
                {
                    DbReader = DbCommand.ExecuteReader();

                    while (DbReader.Read() && !shutdown)
                    {

                        long SourceID = DbReader.GetInt64(1);
                        string CastingSN = DbReader.GetString(2);
                        bool Result = DbReader.GetBoolean(3);

                        WaitCallback callback = new WaitCallback(oComm.RunAgent);
                        CommunicatorState commstate = new CommunicatorState(CastingSN, Result, SourceID);
                        ThreadPool.QueueUserWorkItem(callback, commstate);
                        callback = null;
                        commstate = null;

                    }
                    //Console.WriteLine("Finished Queueing Threads");
                }
                catch (SqlException Ex)
                {
                    Log.LogMessage("There was an error with a query run on the FlexNet Database.", "error");
                    Log.LogMessage(">> " + Ex.Message, "error");
                }
                finally
                {
                    if (DbReader != null) DbReader.Dispose();
                    DbCommand.Dispose();
                }
                ManualResetEvent[] handles = new ManualResetEvent[2] { eventX, ShutdownX };
                WaitHandle.WaitAny(handles);

                //eventX.WaitOne(Timeout.Infinite, true);
            }

これはデータベースから読み取り、見つかったすべてのスレッドをキューに入れ、すべてのスレッドが処理を終了する (eventX リセット イベント) または ShutdownX イベントを待つ必要があると思います

ShutdownX イベントがトリガーされると、シャットダウン bool が true であるため、外側のループは続行されません。その後、スレッドは SQL 接続を閉じて終了する必要があります。これは何も起こりません。何か案は?

4

1 に答える 1

3

を使用してThreadPoolいます。 OnStop伝えられるところによると、スレッドプール内のすべてのタスクが完了するまで呼び出されることはありません。ここここも参照してください。しかし、一部の人々が成功してそれを使用しているように見えるので、私はこれが主ではない、または唯一の原因ではないことに傾いています。

あなたの質問は現在、OnStop呼び出されることはないが、それが発するログメッセージを見たことがあると言っているように思われます。だから私はそれOnStopが呼び出されると思いますが、いくつかのスレッドはそれに気づいていません。

単一のグローバルオブジェクトを使用して、ステートメントでshutdown取得または設定するすべてのコードをラップしてください。lockこれは、原子性または相互排除のためではありません。これは、マルチプロセッサシステムで適切なメモリバリアを確保するためです。

于 2012-05-18T21:28:11.210 に答える