c# – 在应用程序/服务关闭/停止之前等待定时器已过事件完成

概要:
Windows服务和控制台应用程序我正在调用一个公共库,其中包含定时器,定期触发大约需要30秒钟的操作.不过这样做很好

当服务停止或应用程序退出调用并且计时器在ElapsedEventHandler中时,我需要服务停止/应用程序退出等待直到事件处理程序完成.

我已经通过在调用定时器停止方法时检查一个Boolean InEvent属性来实现这个功能.

虽然这是功能,但问题是:这是最好的办法吗?是否有更好的方法可以更好地达到这个目的?

一个问题是我需要避免服务停止请求失败,并显示“服务无法响应停止请求”

这是我的实现

public sealed class TimedProcess : Idisposable
{
    static TimedProcess singletonInstance;
    bool InEvent;
    Timer processtimer;

    private TimedProcess()
    {
    }

    public static TimedProcess Instance
    {
        get
        {
            if (singletonInstance == null)
            {
                singletonInstance = new TimedProcess();
            }

            return singletonInstance;
        }
    }

    public void Start(double interval)
    {
        this.processtimer = new Timer();
        this.processtimer.AutoReset = false;
        this.processtimer.Interval = interval;
        this.processtimer.Elapsed += new ElapsedEventHandler(this.processtimer_Elapsed);
        this.processtimer.Enabled = true;
    }

    public void Stop()
    {
        if (processtimer != null)
        {
            while (InEvent)
            {
            }

            processtimer.Stop();
        }
    }

    void processtimer_Elapsed(object sender,ElapsedEventArgs e)
    {
        try
        {
            InEvent = true;
            // Do something here that takes ~30 seconds
        }
        catch
        {
        }
        finally
        {
            InEvent = false;
            processtimer.Enabled = true;
        }
    }

    public void dispose()
    {
        if (processtimer != null)
        {
            Stop();
            processtimer.dispose();
        }
    }
}

这就是在OnStart / console应用程序main中调用方法

TimedProcess.Instance.Start(1000);

这是在服务OnStop和应用程序main(挂起的按键)中如何调用

TimedProcess.Instance.Stop();

解决方法

可能最简单和最可靠的方法是使用监视器.创建主程序和定时器回调可以访问的对象:
private object _timerLock = new object();

您的主程序在关闭之前尝试锁定:

// wait for timer process to stop
Monitor.Enter(_timerLock);
// do shutdown tasks here

你的定时器回调也锁定它:

void processtimer_Elapsed(object sender,ElapsedEventArgs e)
{
    if (!Monitor.TryEnter(_timerLock))
    {
        // something has the lock. Probably shutting down.
        return;
    }
    try
    {
        // Do something here that takes ~30 seconds
    }
    finally
    {
        Monitor.Exit(_timerLock);
    }
}

主程序一经获取就不应该释放锁.

如果您希望主程序在一段时间后继续关闭,无论是否获得锁定,请使用Monitor.TryEnter.例如,这将等待15秒.

bool gotLock = Monitor.TryEnter(_timerLock,TimeSpan.FromSeconds(15));

如果能够获得锁,则返回值为true.

顺便问一下,我强烈建议您使用System.Threading.Timer而不是System.Timers.Timer.后者阻止例外,最终可能会隐藏错误.如果您的Elapsed事件发生异常,它将永远不会被转义,这意味着您永远不会知道它.有关更多信息,请参阅我的blog post.

相关文章

在要实现单例模式的类当中添加如下代码:实例化的时候:frmC...
1、如果制作圆角窗体,窗体先继承DOTNETBAR的:public parti...
根据网上资料,自己很粗略的实现了一个winform搜索提示,但是...
近期在做DSOFramer这个控件,打算自己弄一个自定义控件来封装...
今天玩了一把WMI,查询了一下电脑的硬件信息,感觉很多代码都...
最近在研究WinWordControl这个控件,因为上级要求在系统里,...