C#中关于Timer定时器重入问题的解决方法

项目中用到了定时器随着服务启动作定时任务,按指定的准点时间定时执行相关操作,但是在指定准点时间内我只想让它执行一次,要避免重入问题的发生。

  首先简单介绍一下timer,这里所说的timer是指的System.Timers.timer,顾名思义,就是可以在指定的间隔是引发事件。官方介绍在这里,摘抄如下:

  1. Timer 组件是基于服务器的计时器,它使您能够指定在应用程序中引发 Elapsed 事件的周期性间隔。然后可通过处理这个事件来提供常规处理。 例如,假设您有一台关键性服务器,必须每周 7 天、每天 24 小时都保持运行。 可以创建一个使用 Timer 的服务,以定期检查服务器并确保系统开启并在运行。 如果系统不响应,则该服务可以尝试重新启动服务器或通知管理员。    基于服务器的 Timer 是为在多线程环境中用于辅助线程而设计的。     服务器计时器可以在线程间移动来处理引发的 Elapsed 事件,这样就可以比 Windows 计时器更精确地按时引发事件。

登录后复制

     那使用这个计时器有啥好处呢?主要因为它是通过.NET Thread Pool实现的、轻量、计时精确、对应用程序及消息没有特别的要求。

 Timer是怎么使用的之前有写过这篇:C# System.Timers.Timer定时器的使用和定时自动清理内存应用

什么叫重入呢?这是一个有关多线程编程的概念:程序中,多个线程同时运行时,就可能发生同一个方法被多个进程同时调用的情况。当这个方法中存在一些非线程安全的代码时,方法重入会导致数据不一致的情况。Timer方法重入是指使用多线程计时器,一个Timer处理还没有完成,到了时间,另一Timer还会继续进入该方法进行处理。

关于定时器的重入问题解决方法尝试如下

1、使用锁lock(Object)的方法来防止重入,表示一个Timer处理正在执行,下一个Timer发生的时候发现上一个没有执行完就等待执行,适用重入很少出现的场景。在触发的方法中加入lock,这样当线程2进入触发的方法中,发现已经被锁,会等待锁中的代码处理完在执行,代码如下:

  1. private static System.Timers.Timer aTimer = new System.Timers.Timer(); private static object loker=new object();   ///         /// 设置定时器        ///         public static void SetTimer()        {            //读取配置时间            try            {                aTimer.Interval = 30000;                aTimer.Elapsed += new System.Timers.ElapsedEventHandler(OnTimedEvent);                aTimer.AutoReset = true;//每到指定时间Elapsed事件是到时间就触发                aTimer.Enabled = true; //指示 Timer 是否应引发 Elapsed 事件。            }            catch (Exception ex)            {                LogManager.RecordLog(LogType.Error, "ipad数据同步出错:" +ex.Message,ex);            }        }        private static void OnTimedEvent(Object source, ElapsedEventArgs e)        {            //如果当前时间是为配置的准点时间就进来            var time =Convert.ToInt32( SynchronousHelper.AppConfig.get_Items("SycTime"));            if (DateTime.Now.Hour == time && DateTime.Now.Minute == 0)            {                //lock,这样当线程2进入触发的方法中,发现已经被锁,会等待锁中的代码处理完在执行                lock (loker)                {                    LogManager.RecordLog(LogType.Info, "数据开始同步时间:" + e.SignalTime, null);                    SetTimerStart();                    System.Threading.Thread.Sleep(60000); //执行完越过当前分钟,使整点内只能进来一次                }            }        }

登录后复制

2.置一个标志,表示一个Timer处理正在执行,下一个Timer发生的时候发现上一个没有执行完就放弃(注意这里是放弃,而不是等待哦,看看执行结果就明白啥意思了)执行,适用重入经常出现的场景。在多线程下给inTimer赋值不够安全,Interlocked.Exchange提供了一种轻量级的线程安全的给对象赋值的方法(感觉比较高上大,也是比较推荐的一种方法)。

  1. private static System.Timers.Timer aTimer = new System.Timers.Timer(); private static int inTimer = 0;        ///         /// 设置定时器        ///         public static void SetTimer()        {            //读取配置时间            try            {                aTimer.Interval = 30000; //半分钟触发一次                aTimer.Elapsed += new System.Timers.ElapsedEventHandler(OnTimedEvent);                aTimer.AutoReset = true;//每到指定时间Elapsed事件是到时间就触发                aTimer.Enabled = true; //指示 Timer 是否应引发 Elapsed 事件。            }            catch (Exception ex)            {                LogManager.RecordLog(LogType.Error, "ipad数据同步出错:" +ex.Message,ex);            }        }        private static void OnTimedEvent(Object source, ElapsedEventArgs e)        {            //如果当前时间是为配置的准点时间就进来            var time =Convert.ToInt32( SynchronousHelper.AppConfig.get_Items("SycTime"));            if (DateTime.Now.Hour == time && DateTime.Now.Minute == 0)            {                //inTimer设置一个标志,表示一个Timer处理正在执行,下一个Timer发生的时候发现上一个没有执行完就放弃                if (Interlocked.Exchange(ref inTimer, 1) == 0)                {                    LogManager.RecordLog(LogType.Info, "数据开始同步时间:" + e.SignalTime, null);                    SetTimerStart();                    System.Threading.Thread.Sleep(60000); //执行完等待越过当前分钟,使整点内只能进来一次                    Interlocked.Exchange(ref inTimer, 0);                }            }        }

登录后复制

稍微总结一下,timer是一个使用挺简单的类,拿来即用,这里主要总结了使用timer时重入问题的解决,以前也没思考过这个问题,解决方案也挺简单。这里的解决方案同时也适用多线程的重入问题。

 

以上就是C#中关于Timer定时器重入问题的解决方法的详细内容,更多请关注【创想鸟】其它相关文章!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

点点赞赏,手留余香

给TA打赏
共0人
还没有人赞赏,快来当第一个赞赏的人吧!
    编程技术

    ASP.NET教程--MVC中SignalR的基础讲解

    2025-3-5 1:37:59

    编程技术

    C#如何实现自动更新本地程序的实例分析

    2025-3-5 1:38:15

    0 条回复 A文章作者 M管理员
    欢迎您,新朋友,感谢参与互动!
      暂无讨论,说说你的看法吧
    个人中心
    购物车
    优惠劵
    今日签到
    私信列表
    搜索