至于C#中Timer定时器的重入难点解决方式(也适用于二十四线程)

品类中用到了定时器随着服务运行作定时义务,按钦点的准点时间定时执行有关操作,可是在钦定准点时间内自个儿只想让它实施几次,要避免重入难点的发生。

C#, 
首先不难介绍一下timer,那里所说的timer是指的System.Timers.timer,顾名思义,就是可以在钦定的间距是诱惑风云。官方介绍在这里.aspx),摘抄如下:

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

     那使用那个计时器有吗好处呢?首要因为它是通过.NET Thread
Pool完结的、轻量、计时精确、对应用程序及音信尚未特其余须要。

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

怎么样叫重入呢?这是三个有关多线程编程的概念:程序中,多少个线程同时运营时,就只怕发生同3个办法被多个经过同时调用的状态。当这一个方法中存在部分非线程安全的代码时,方法重入会促成数据不一样的情景。Timer方法重入是指利用十二线程计时器,三个Timer处理还尚未旗开得胜,到了时间,另一Timer还会再三再四进入该办法开展拍卖。

至于定时器的重入难点解决办法尝试如下

一 、使用锁lock(Object)的法门来防患重入,表示五个提姆er处理正在实施,下3个Timer暴发的时候发现上多个不曾实施完就等候执行,适用重入很少出现的场景。在触发的办法中进入lock,这样当线程2进入触发的点子中,发现早已被锁,会等待锁中的代码处理完在履行,代码如下:

 private static System.Timers.Timer aTimer = new System.Timers.Timer();
 private static object loker=new object();
   /// <summary>
        /// 设置定时器
        /// </summary>
        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.置1个注脚,表示1个Timer处理正在进行,下多少个Timer暴发的时候发现上二个尚无履行完就放弃(注意这里是屏弃,而不是等待哦,看看执行结果就理解啥意思了)执行,适用重入常常出现的情景。在多线程下给inTimer赋值不够安全,Interlocked.Exchange提供了一种轻量级的线程安全的给目的赋值的格局(感觉相比高上大,也是相比推荐的一种艺术)。

 private static System.Timers.Timer aTimer = new System.Timers.Timer();
 private static int inTimer = 0;

        /// <summary>
        /// 设置定时器
        /// </summary>
        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时重入难题的消除,之前也没考虑过那个标题,消除方案也挺简单。那里的缓解方案同时也适用二十四线程的重入难题。

 

相关文章