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 接続を閉じて終了する必要があります。これは何も起こりません。何か案は?