我用 C# 编写了一个作为 Windows 服务运行的程序。应用程序启动并运行良好,但是当我使用管理控制台停止服务时,没有调用 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();
}
该日志消息永远不会被写入日志文件。
任何帮助,将不胜感激。我什至不知道从哪里开始寻找。谢谢。
编辑 我解决了锁定后台线程的问题。我还注释掉了日志语句,所以我知道日志语句不会导致问题。
除了布尔标志之外,我还添加了一个 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 事件,外部循环不应该继续,因为 shutdown bool 为真,然后线程关闭它的 SQL 连接并应该终止。这一切都不会发生。有任何想法吗?