Windows服务OnStop等待完成处理

cri*_*jax 14 .net c# wcf windows-services single-threaded

我实际上在VS 2012/.NET 4.5中开发了一个Windows服务.

该服务遵循以下代码段的方案:

  • 使用计时器
  • 每隔几分钟执行一些所需的操作.
  • 该过程大约需要10分钟才能完成
  • 我在服务中使用单个线程

我担心的是,如果有人通过管理控制台停止服务,它可能只是在服务正在进行的过程中.

我已经做了一些关于停止请求停止的Windows服务的阅读,但有点迷失.有时创建WorkerThreads,有时会创建ManualResetEvents,但到目前为止,我无法完全掌握Windows服务的最佳前进方法.

我需要等到处理在onStop方法中正确完成后再停止Windows服务.

那么最好的方法是什么,还要考虑下面的代码片段?

谢谢大家!

namespace ImportationCV
{
    public partial class ImportationCV : ServiceBase
    {
        private System.Timers.Timer _oTimer;       

        public ImportationCV()
        {
            InitializeComponent();

            if (!EventLog.SourceExists(DAL.Utilities.Constants.LOG_JOURNAL))
            {
                EventLog.CreateEventSource(DAL.Utilities.Constants.LOG_JOURNAL,     DAL.Utilities.Constants.SOURCE_JOURNAL);
            }

            EventLog.Source = DAL.Utilities.Constants.SOURCE_JOURNAL;
            EventLog.Log = DAL.Utilities.Constants.LOG_JOURNAL;
        }

        protected override void OnStart(string[] args)
        {            
            int intDelai = Properties.Settings.Default.WatchDelay * 1000;

            _oTimer = new System.Timers.Timer(intDelai);
            _oTimer.Elapsed += new ElapsedEventHandler(this.Execute);

            _oTimer.Start();           

            EventLog.WriteEntry(DAL.Utilities.Constants.LOG_JOURNAL, "Service " + DAL.Utilities.Constants.SERVICE_TITLE + " started at " + DateTime.Now.ToString("HH:mm:ss"), EventLogEntryType.Information);
        }

        protected override void OnStop()
        {

            if (_oTimer != null && _oTimer.Enabled)
            {
                _oTimer.Stop();
                _oTimer.Dispose();
            }

            EventLog.WriteEntry(DAL.Utilities.Constants.LOG_JOURNAL, "Service " + DAL.Utilities.Constants.SERVICE_TITLE + " stopped at " + DateTime.Now.ToString("HH:mm:ss"), EventLogEntryType.Information);
        }

        private void Execute(object source, ElapsedEventArgs e)
        {
            _oTimer.Stop();

            try
            {                
                //Process


            }
            catch (Exception ex)
            {
                EventLog.WriteEntry(DAL.Utilities.Constants.LOG_JOURNAL, (ex.StackTrace + ("\r\n" + ex.Message)), EventLogEntryType.Error);
            }

            _oTimer.Start();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Mat*_*vis 19

作为测试用例,我System.Threading.Thread.Sleep(500000)OnStop()我的Windows服务的回调中调用了一个.我启动了服务然后停止了它.我得到了带有进度条的窗口,指示服务控制管理器(SCM)正在尝试停止服务.大约2分钟后,我得到了SCM的回复:

在此输入图像描述

在我关闭此窗口后,我在SCM中的服务状态变为Stopping,我注意到该服务继续在任务管理器中运行.睡眠过后(将近6分钟后),过程停止.刷新SCM窗口显示服务不再运行.

我从这里拿走了一些东西.首先,OnStop()应该真正尝试及时停止服务,就像玩好系统一样.其次,根据您的OnStop()方法的结构,您可以强制服务忽略抢先请求停止,而不是在您这样说时停止.不建议这样做,但看起来你可以这样做.

至于你的特殊情况,你必须要理解的是System.Timers.Timer.Elapsed事件在一个ThreadPool线程上触发.根据定义,这是一个后台线程,这意味着它不会使应用程序保持运行.当告知服务关闭时,系统将停止所有后台线程,然后退出该进程.因此,尽管被SCM告知要关闭,但是关于保持处理完成直到完成的关注不会发生在你当前结构化的方式上.为此,您需要创建一个正式System.Threading.Thread对象,将其设置为前台线程,然后使用计时器来触发此线程执行(而不是在Elapsed回调中完成).

所有这些都说,我仍然认为你想要与系统很好地配合,这意味着在要求时及时关闭服务.例如,如果您需要重启机器会发生什么?我没有对它进行测试,但是如果你强制你的服务继续运行直到处理完成,那么系统可能会等到进程完成之后再实际重启.这不是我想要的服务.

所以我建议两件事之一.第一种选择是将处理分解为可以单独完成的不同块.每个块完成后,检查服务是否正在停止.如果是这样,请正常退出线程.如果无法做到这一点,那么我会向您的处理介绍类似于交易的内容.假设您需要与一堆数据库表进行交互,并且一旦启动就中断流程会出现问题,因为数据库可能处于错误状态.如果数据库系统允许事务处理,则相对容易.如果没有,那么在内存中执行所有处理并在最后一秒提交更改.这样,您只会在提交更改时阻止关闭,而不是在整个持续时间内阻塞.值得一提的是,我更喜欢使用ManualResetEvent将断点命令传递给线程.

为了避免进一步漫无目的,我会在这里切断它.HTH.

编辑:

这是袖口,所以我不会验证它的准确性.我会解决你(或其他人)可能发现的任何问题.

定义两个ManualResetEvent对象,一个用于关闭通知,另一个用于处理通知,以及Thread对象.将OnStart()回调更改为:

using System.Threading;
using Timer = System.Timers.Timer; // both Threading and Timers have a timer class

ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
ManualResetEvent _processEvent  = new ManualResetEvent(false);
Thread _thread;
Timer _oTimer;

protected override void OnStart(string[] args)
{
    // Create the formal, foreground thread.
    _thread = new Thread(Execute);
    _thread.IsBackground = false;  // set to foreground thread
    _thread.Start();

    // Start the timer.  Notice the lambda expression for setting the
    // process event when the timer elapses.
    int intDelai = Properties.Settings.Default.WatchDelay * 1000;
    _oTimer = new Timer(intDelai);
    _oTimer.AutoReset = false;
    _oTimer.Elapsed += (sender, e) => _processEvent.Set();
    _oTimer.Start();
}
Run Code Online (Sandbox Code Playgroud)

将您的Execute()回调更改为以下内容:

private void Execute()
{
    var handles = new WaitHandle[] { _shutdownEvent, _processEvent };

    while (true)
    {
        switch (WaitHandle.WaitAny(handles))
        {
            case 0:  // Shutdown Event
                return; // end the thread
            case 1:  // Process Event
                Process();
                _processEvent.Reset();  // reset for next time
                _oTimer.Start();        // trigger timer again
                break;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

创建这样的Process()方法:

private void Process()
{
    try
    {
        // Do your processing here.  If this takes a long time, you might
        // want to periodically check the shutdown event to see if you need
        // exit early.
    }
    catch (Exception ex)
    {
        // Do your logging here...

        // You *could * also shutdown the thread here, but this will not
        // stop the service.
        _shutdownEvent.Set();
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,在OnStop()回调中,触发线程关闭:

protected override void OnStop()
{
    _oTimer.Stop();  // no harm in calling it
    _oTimer.Dispose();

    _shutdownEvent.Set();  // trigger the thread to stop
    _thread.Join();        // wait for thread to stop
}
Run Code Online (Sandbox Code Playgroud)

  • 我严重怀疑重启会等待进程停止.病毒可以使用它来停止重启.停止中的错误可能会停止重启.http://stackoverflow.com/questions/2008807/forcing-windows-to-wait-for-a-service-to-stop-when-it-is-shutting-down (2认同)