未调用 Windows 服务 OnStop() [英] Windows Service OnStop() not called

查看:30
本文介绍了未调用 Windows 服务 OnStop()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用 C# 编写了一个作为 Windows 服务运行的程序.应用程序启动并运行良好,但当我使用管理控制台停止服务时,没有调用 OnStop 函数.

OnStart 方法为主程序启动一个后台线程,该后台线程启动另一个线程和一个线程池来为它工作.

OnStop 我设置了一个布尔标志,所有其他线程都会检查该标志以查看它们是否应该停止处理.然后线程应该全部完成,程序应该结束.

这是我的 OnStart 代码

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

该代码有效.下面是 OnStop 的代码,据我所知,它永远不会被调用.

protected override void OnStop(){Log.LogMessage("从操作系统中捕获到关机信号", "debug");base.OnStop();关机=真;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();关机=真;关机X.Set();//这是ManualResetEventmainProgram.Join(15000);if (mainProgram.IsAlive) mainProgram.Abort();}

应该停止代码的地方在 mainProgram.RunAgent() 函数中(这是它自己的线程)而(!关机){

 SqlCommand DbCommand = dbConnection.CreateCommand();DbCommand.CommandText = "SELECT id, SourceID, CastingSN, Result FROM db_owner.queue";SqlDataReader DbReader = null;尝试{DbReader = DbCommand.ExecuteReader();while (DbReader.Read() && !shutdown){long SourceID = DbReader.GetInt64(1);string CastingSN = DbReader.GetString(2);bool 结果 = DbReader.GetBoolean(3);WaitCallback callback = new WaitCallback(oComm.RunAgent);CommunicatorState commstate = new CommunicatorState(CastingSN, Result, SourceID);ThreadPool.QueueUserWorkItem(callback, commstate);回调 = 空;commstate = 空;}//Console.WriteLine("完成排队线程");}捕获(SqlException Ex){Log.LogMessage("在 FlexNet 数据库上运行查询时出错.", "error");Log.LogMessage(">>" + Ex.Message, "error");}最后{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 连接并应终止.这些都不会发生.有什么想法吗?

解决方案

您正在使用 ThreadPool.据报道,OnStop 从未被调用 直到线程池中的所有任务完成.另请参阅此处此处.但是,我倾向于这不是主要原因或唯一原因,因为有些人 似乎成功使用它.

在我看来,您的问题目前表明 OnStop 永远不会被调用,但您已经看到它发出的日志消息.所以我假设 OnStop 确实被调用了,但一些线程没有注意到.

请使用单个全局对象将所有获取或设置 shutdown 的代码封装在 lock 语句中.这不是为了原子性或互斥.这是为了在多处理器系统上确保适当的内存屏障.

I've written a program in C# that runs as a Windows Service. The application starts up and runs fine, but the OnStop function doesn't get called when I use the Management Console to stop the service.

The OnStart method starts a background thread for the main program, and that background thread starts another thread and a ThreadPool to do work for it.

OnStop I set a boolean flag that all the other threads check in order to see if they should stop processing. The threads should all then finish, and the program should end.

Here's the code for my OnStart

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

That code works. Below is the code for OnStop, which as far as I can tell doesn't ever get called.

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();
    }

That log message never gets written to the log file.

Any help would be appreciated. I don't even know where to start looking. Thanks.

EDIT I solved the problem that was locking the background thread. I also commented out that logging statement, so I know the log statement isn't causing the problem.

I added a ManualResetEvent in addition to the boolean flag. The OnStop now looks like this:

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();
    }

The place this should stop the code is here in the mainProgram.RunAgent() function (which is its own thread) 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);
            }

I think this should read from the database, queue up all the threads it finds, then wait for either all the threads to finish processing (the eventX reset event) or the ShutdownX Event.

Once the ShutdownX event is triggered, the outer loop shouldn't continue because the shutdown bool is true, then the thread closes it's SQL connections and should terminate. None of this happens. Any ideas?

解决方案

You are using ThreadPool. OnStop is reportedly never called until all tasks in the thread pool complete. See also here and here. However, I am leaning towards this not being the main or only cause as some people seem to be using it with success.

It seems to me that your question currently says that OnStop never gets called but that you have seen the log message that it emits. So I assume that OnStop does get called but that some of the threads do not notice that.

Please wrap all code that gets or sets shutdown in a lock statement, using a single global object. This is not for atomicity or mutual exclusion. This is to ensure proper memory barriers on a multiprocessor system.

这篇关于未调用 Windows 服务 OnStop()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆