Lösung für das Problem des Timer-Timer-Wiedereintritts in C#

黄舟
Freigeben: 2017-08-11 13:21:38
Original
2708 Leute haben es durchsucht

Im Projekt wird ein Timer verwendet, um geplante Aufgaben beim Start des Dienstes auszuführen, und die relevanten Vorgänge werden zur angegebenen pünktlichen Zeit ausgeführt. Ich möchte jedoch, dass er nur einmal innerhalb der angegebenen pünktlichen Zeit ausgeführt wird, um einen erneuten Eintritt zu vermeiden Probleme.

Lassen Sie uns zunächst kurz den Timer vorstellen. Der hier erwähnte Timer bezieht sich auf System.Timers.timer. Wie der Name schon sagt, kann er Ereignisse in bestimmten Intervallen auslösen. Die offizielle Einführung finden Sie hier und der Auszug lautet wie folgt:


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

Welche Vorteile bietet die Verwendung dieses Timers? Hauptsächlich, weil es über den .NET Thread Pool implementiert wird, leichtgewichtig ist, ein genaues Timing aufweist und keine besonderen Anforderungen an Anwendungen und Nachrichten stellt.

So verwenden Sie den Timer Ich habe diesen Artikel bereits geschrieben: Die Verwendung des C#-System.Timers.Timer-Timers und die Anwendung der automatischen Speicherbereinigung in regelmäßigen Abständen

Was ist Wiedereintritt? ? Dies ist ein Konzept der Multithread-Programmierung: Wenn in einem Programm mehrere Threads gleichzeitig ausgeführt werden, kann dieselbe Methode von mehreren Prozessen gleichzeitig aufgerufen werden. Wenn diese Methode nicht threadsicheren Code enthält, führt der Wiedereintritt der Methode zu Dateninkonsistenzen. Der Wiedereintritt der Timer-Methode bezieht sich auf die Verwendung von Multithread-Timern. Bevor die Verarbeitung eines Timers abgeschlossen ist und die Zeit abgelaufen ist, tritt der andere Timer weiterhin in die Verarbeitungsmethode ein.

Versuchen Sie die folgenden Lösungen für das Timer-Wiedereintrittsproblem:

1. Verwenden Sie die lock(Object)-Methode, um einen Wiedereintritt zu verhindern und anzuzeigen, dass ein Timer verarbeitet wird. Wenn der nächste Timer auftritt und festgestellt wird, dass der vorherige nicht ausgeführt wurde, wartet auf die Ausführung , was für Szenarien geeignet ist, in denen ein Wiedereintritt selten auftritt. Fügen Sie der auslösenden Methode eine Sperre hinzu, sodass Thread 2, wenn er die auslösende Methode betritt und feststellt, dass sie gesperrt ist, auf die Verarbeitung des Codes in der Sperre wartet, bevor er ausgeführt wird. Der Code lautet wie folgt:

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); //执行完越过当前分钟,使整点内只能进来一次
                }
            }
        }
Nach dem Login kopieren

2. Setzen Sie ein Flag, das anzeigt, dass ein Timer-Prozess ausgeführt wird. Wenn der nächste Timer auftritt, wird festgestellt, dass der vorherige nicht ausgeführt wurde und gibt auf (beachten Sie, dass dies der Fall ist). Aufgeben, nicht Warten. Sie werden verstehen, was es bedeutet, wenn Sie sich die Ausführungsergebnisse ansehen.) Ausführung, anwendbar auf Szenarien, in denen ein Wiedereintritt erfolgt. Das Zuweisen von Werten zu inTimer ist unter Multithreading nicht sicher genug. Exchange bietet eine einfache, threadsichere Methode zum Zuweisen von Werten zu Objekten (sie fühlt sich fortgeschrittener an und ist auch eine empfehlenswertere Methode).

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);
                }
            }
        }
Nach dem Login kopieren

Zusammenfassend lässt sich sagen, dass Timer eine sehr einfache Klasse ist, die sofort verwendet werden kann. Hier fassen wir hauptsächlich die Lösung des Wiedereintrittsproblems bei der Verwendung von Timer zusammen. Ich habe noch nie über dieses Problem nachgedacht Es ist ganz einfach. Die Lösung hier gilt auch für Multithread-Wiedereintrittsprobleme.

Das obige ist der detaillierte Inhalt vonLösung für das Problem des Timer-Timer-Wiedereintritts in C#. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage