ホームページ >バックエンド開発 >C#.Net チュートリアル >C# におけるタイマーの再入可能問題の解決策

C# におけるタイマーの再入可能問題の解決策

黄舟
黄舟オリジナル
2017-08-11 13:21:382747ブラウズ

プロジェクトでは、サービスの開始時にスケジュールされたタスクを実行するためにタイマーが使用され、関連する操作は指定された時間どおりに実行されますが、再入の問題を避けるために、指定された時間内に 1 回だけ実行する必要があります。

まず、タイマーについて簡単に説明します。ここで言うタイマーとは、名前が示すように、指定した間隔でイベントをトリガーすることができます。公式の紹介文はここにあり、その抜粋は次のとおりです:


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

では、このタイマーを使用する利点は何でしょうか?その主な理由は、.NET スレッド プールを通じて実装され、軽量で正確なタイミングを備え、アプリケーションやメッセージに特別な要件がないためです。

タイマーの使用方法については、以前に次の記事を書きました: C# システムの使用。これはマルチスレッド プログラミングに関する概念です。プログラム内で複数のスレッドが同時に実行されると、同じメソッドが複数のプロセスによって同時に呼び出される可能性があります。このメソッドにスレッドセーフでないコードが含まれている場合、メソッドの再入によりデータの不整合が発生します。タイマー メソッドの再入とは、1 つのタイマーの処理が完了する前に、時間が経過すると、他のタイマーが処理のためにメソッドに入り続けることを指します。

タイマーの再入の問題に対して次の解決策を試してください:

1. 再入を防ぐためにロック (オブジェクト) メソッドを使用します。これは、次のタイマーが発生したときに、タイマー処理が実行されていることがわかります。実行後は、

実行を待つだけ。これは、再入がほとんど発生しないシナリオに適しています。トリガー メソッドにロックを追加します。これにより、スレッド 2 がトリガー メソッドに入り、ロックされていることを確認すると、ロック内のコードが処理されるのを待ってから実行されます。コードは次のとおりです。タイマー処理が実行中であることを示すフラグを設定します。次のタイマーが発生すると、前のタイマーが実行されていないことがわかります。 (これは待機ではなく諦めていることに注意してください。これが何を意味するかはわかります)実行結果を見ることを意味します)。リエントリーが頻繁に発生するシナリオに適しています。 inTimer への値の割り当ては、マルチスレッド環境では十分に安全ではありません。 Interlocked.Exchange は、オブジェクトに値を割り当てる軽量のスレッドセーフな方法を提供します (より高度な方法であり、より推奨される方法でもあります)。

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

少しまとめると、timer はとてもシンプルなクラスで、すぐに使えます。 ここでは主に、これまで考えたこともなかった、timer を使用する際のリエントラント問題の解決方法をまとめます。は非常に簡単です。ここでの解決策は、マルチスレッドの再入可能の問題にも当てはまります。

以上がC# におけるタイマーの再入可能問題の解決策の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。