Maison  >  Article  >  développement back-end  >  Solution au problème de la réentrée du minuteur en C#

Solution au problème de la réentrée du minuteur en C#

黄舟
黄舟original
2017-08-11 13:21:382658parcourir

Dans le projet, une minuterie est utilisée pour effectuer des tâches planifiées au démarrage du service, et les opérations pertinentes sont effectuées à l'heure ponctuelle spécifiée. Cependant, je souhaite qu'elle ne soit exécutée qu'une seule fois dans l'heure ponctuelle spécifiée pour éviter la réentrée. problèmes.

Tout d'abord, présentons brièvement le timer. Le timer mentionné ici fait référence à System.Timers.timer. Comme son nom l'indique, il peut déclencher des événements à des intervalles spécifiés. L'introduction officielle est ici, et l'extrait est le suivant :


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

Alors, quels sont les avantages d'utiliser ce timer ? Principalement parce qu'il est implémenté via le pool de threads .NET, qu'il est léger, qu'il a un timing précis et qu'il n'a aucune exigence particulière pour les applications et les messages.

Comment utiliser Timer J'ai déjà écrit cet article : L'utilisation de C# System.Timers.Timer timer et l'application du nettoyage automatique de la mémoire à intervalles réguliers

Qu'est-ce que la réentrance ? Il s'agit d'un concept de programmation multithread : dans un programme, lorsque plusieurs threads s'exécutent en même temps, la même méthode peut être appelée par plusieurs processus en même temps. Lorsqu'il y a du code non thread-safe dans cette méthode, la réentrance de la méthode entraînera une incohérence des données. La réentrance de la méthode du minuteur fait référence à l'utilisation de minuteurs multithreads avant que le traitement d'un minuteur ne soit terminé, lorsque le temps est écoulé, l'autre minuteur continuera à entrer dans la méthode pour le traitement.

Essayez les solutions suivantes au problème de réentrée du minuteur :

1. Utilisez la méthode lock(Object) pour empêcher la réentrée, indiquant qu'un minuteur est en cours d'exécution, lorsque le prochain Timer se produit, il s'avère que le précédent n'a pas été exécuté et attend l'exécution , ce qui convient aux scénarios où la réentrance se produit rarement. Ajoutez un verrou à la méthode de déclenchement, de sorte que lorsque le thread 2 entre dans la méthode de déclenchement et constate qu'elle a été verrouillée, il attendra que le code dans le verrou soit traité avant de s'exécuter. Le code est le suivant :

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. Définissez un indicateur, indiquant qu'un processus Timer est en cours d'exécution. Lorsque le prochain Timer se produit, il s'avère que le précédent n'a pas été exécuté et

abandonne (notez que c'est le cas). abandonner, ne pas attendre. Vous comprendrez ce que cela signifie en regardant les résultats de l'exécution) Exécution, applicable aux scénarios de réentrée. L'attribution de valeurs à inTimer n'est pas suffisamment sûre sous le multithreading. Interlocked.Exchange fournit une méthode légère et sécurisée pour attribuer des valeurs aux objets (elle semble plus avancée et constitue également une méthode plus recommandée).

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);
                }
            }
        }
Pour résumer un peu, timer est une classe très simple à utiliser, et elle peut être utilisée immédiatement. Ici, nous résumons principalement la solution au problème de réentrance lors de l'utilisation de timer. problème avant, et la solution C'est assez simple. La solution ici s'applique également aux problèmes de réentrée multithread.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn