C# 解决Timer定时器在整点重复进入
本文最后更新于174 天前,其中的信息可能已经过时,如有错误请发送邮件到2289035571@QQ.COM

感谢 TurboAI对本博客的的大力赞助。 创作不易,如果您觉得有帮助,请支持LIncol29!

在项目中遇到一个需求,在整点的时候执行一个方法。(保存数据、处理数据等),此时我们需要一个Timer定时器,当整点的时候可以指定特定事件。那如何解决Timer定时器在整点重复进入方法的问题,继续往下看。

这里我们使用一个实例:当运行到指定时间段的时候,文字开始滚动(实现跑马灯效果)

界面效果

在Form窗体中,定义一个label标签,内容是:☆123☆

代码

using System;
using Timers = System.Timers;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;

namespace MyTimer
{
    public partial class Form1 : Form
    {
        private Timers.Timer timer1;
        private int inTimer;

        public Form1()
        {
            InitializeComponent();
            timer1 = new Timers.Timer()
            {
                Interval = 100,
                Enabled = true,
                AutoReset = true
                };
            timer1.Elapsed += Timer1_Elapsed;
            this.StartPosition = FormStartPosition.CenterScreen;
        }

        private void Timer1_Elapsed(object sender, Timers.ElapsedEventArgs e)
        {
            DateTime currentTime = DateTime.Now;
            if(currentTime.Second == 10 || currentTime.Second == 20 || currentTime.Second == 30 || currentTime.Second == 40 || currentTime.Second == 50)
            {
                #region 第一种方法
                    //inTimer设置一个标志,表示一个Timer处理正在执行,下一个Timer发生的时候发现上一个没有执行完就放弃
                    if (Interlocked.Exchange(ref inTimer, 1) == 0)
                    {
                        Debug.WriteLine($"数据开始同步时间:{e.SignalTime}");

                        //第一个重载是从当前索引开始截取后面的字符串 + 第二个重载是从当前索引开始,长度是多少
                        this.Invoke(new Action(() =>
                                           {
                                               lbl.Text = lbl.Text.Substring(1) + lbl.Text.Substring(0, 1);
                                           }));

                        System.Threading.Thread.Sleep(60000); //执行完等待越过当前分钟,使整点内只能进来一次
                        Interlocked.Exchange(ref inTimer, 0);
                    }
                #endregion

                    #region 第二种方法
                    if (Math.Abs(currentTime.Millisecond) < 80  )
                    {                
                        this.Invoke(new Action(() =>
                                           {
                                               lbl.Text = lbl.Text.Substring(1) + lbl.Text.Substring(0, 1);
                                           }));
                    }
                #endregion
                }
        }     
    }
}

代码解析

从当前代码实例解析,首先我们可以知道在窗体初始化的时候给定时器设置了100ms的间隔,也就是说100ms定时器就会触发一次

timer正常如果不做任何设置情况下,就是定时器在10,20,30,40,50S的时候会进入这个if判断,在这里面去执行自己的需求方法。此时问题出现:timer的间隔时间为100ms,可能会重复进入多次if语句去执行方法,但是实际需求就是只执行一次方法。

if(currentTime.Second == 10 || currentTime.Second == 20 || currentTime.Second == 30 || currentTime.Second == 40 || currentTime.Second == 50)

第一种方法——设置标志位

  1. 设置一个标志位,

private int inTimer;

  1. 当inTimer为1的时候表示Timer正在处理,如果此时下一个Timer进入这个判断发现没有执行完就放弃

if(Interlocked.Exchange(ref inTimer, 1) == 0 )

  1. 执行整点需要运行的方法
  2. 此时可以设置一个延时,执行完越过整点,使整点只能进入一次
  3. 将inTimer标志位设置为初始状态0Interlocked.Exchange(ref inTimer, 0);
#region 第一种方法
//inTimer设置一个标志,表示一个Timer处理正在执行,下一个Timer发生的时候发现上一个没有执行完就放弃
if (Interlocked.Exchange(ref inTimer, 1) == 0)
{
    Debug.WriteLine($"数据开始同步时间:{e.SignalTime}");

    //第一个重载是从当前索引开始截取后面的字符串 + 第二个重载是从当前索引开始,长度是多少
    this.Invoke(new Action(() =>
                           {
                               lbl.Text = lbl.Text.Substring(1) + lbl.Text.Substring(0, 1);
                           }));

    System.Threading.Thread.Sleep(60000); //执行完等待越过当前分钟,使整点内只能进来一次
    Interlocked.Exchange(ref inTimer, 0);
}
#endregion
  • 优点:简单易懂,适用于简单的时间控制需求。
  • 缺点:可能不够精确,受系统时间的影响较大,不适用于需要精确控制的场景。

第二种方法——设置定时器前后进入的误差时间

直接使用Math.Abs方法,判断当前毫秒是否小于80,因为timer的间隔为100,可以保证不会第二次进入。

#region 第二种方法
if (Math.Abs(currentTime.Millisecond) < 80  )
{                
    this.Invoke(new Action(() =>
                           {
                               lbl.Text = lbl.Text.Substring(1) + lbl.Text.Substring(0, 1);
                           }));
}
#endregion
  • 优点:能够精确控制并发访问,避免竞态条件,适用于多线程环境下的任务调度。
  • 缺点:相对较复杂,需要考虑线程安全和并发问题,适用于需要精确控制的场景。
创作不易,如果您觉得有帮助,请支持LIncol29!
如有需要,请至网站地图学习本博客的教程
博客订阅:通过RSS或关注公众号[Lincol的编程世界] | 广告招租与合作请留言
本文链接:https://www.lincol29.cn/timer_2024-04-16
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0协议转载请注明文章地址及作者哦~

评论

  1. edison
    Windows Edge
    浙江省湖州市 电信/IDC机房
    5 月前
    2024-4-29 14:11:19

    这个非常的好用,支持一下

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇