等待计时器,每隔一段时间运行一次?

时间:2011-09-20 17:16:39

标签: c# .net multithreading .net-4.0 timer

使用C#,.NET Framework 4.0。 我有3个TimeSpan对象设置为20分钟,30分钟,45分钟。我想让Timer只在确切的分钟间隔内执行,无论何时实际启动任何计时器。 我需要定时器触发看起来像这样(每小时):

timerA 1:00
timerB 1:00
timerA 1:20
timerB 1:30
timerA 1:40
timerC 1:45
timerA 2:00
timerB 2:00
timerA 2:20
timerB 2:30
timerA 2:40
timerC 2:45

我认为Waitable计时器是正确的举动,但由于缺乏简单的例子,我猜不是。获得此功能的最佳方法是什么(如果可能的话,我希望避免时钟漂移,但我现在急需任何事情)?我没有和Waitable结婚。我也明白,timerC只能每小时运行一次,这很好,因为它设置为仅在每小时的第45分钟运行。

注意 - 我还没准备好使用Quartz.NET。

感谢。

2 个答案:

答案 0 :(得分:1)

我能得到的最接近的是在目标时间'爬行',使用等待,(睡眠(),超时事件,一些线程计时器或经典'主线程窗口计时器),设置为数字的一半“现在”和目标时间之间的毫秒数,由实时时钟计算得出。如果剩余的ms大于某个限制(例如500),则重新计算剩余的ms并再次等待。当剩余的ms低于限制时,开始循环实时时钟直到达到或超过目标,然后调用TimeSpan对象的timeout()方法。

您可以将TimeSpan对象放在超时时间排序队列中,这样您只需要一个等待。如果您遇到TimeSpan事件经常“同时”发生的情况,这可能更准确,因为目标时间接近时只有一个线程循环。

RGDS, 马丁

答案 1 :(得分:1)

我认为这将为您完成工作:

static void Main(string[] args)
{
    StartTimer(TimeSpan.FromMinutes(20.0), "TimerA", true);
    StartTimer(TimeSpan.FromMinutes(30.0), "TimerB", true);
    StartTimer(TimeSpan.FromMinutes(45.0), "TimerC", true);

    Console.WriteLine("Press any key to exit...");
    Console.ReadLine();
}

启动计时器功能启动计时器并将其返回(如果需要参考)。这里的关键是你给它定时器名称,你告诉它你是否要将计时器与整个小时对齐。如果您不想与整个小时对齐,则计时器将立即以指定的频率启动。

public static Timer StartTimer(TimeSpan frequency, string timerName, bool alignToHour)
{
    if (alignToHour)
    {
        return new Timer(OnTimerTick, timerName, ComputeDelay(frequency), frequency);
    }
    else
    {
        return new Timer(OnTimerTick, timerName, TimeSpan.Zero, frequency);
    }
}

计时器滴答时将触发的函数。

public static void OnTimerTick(object state)
{
    Console.WriteLine((string)state + " " + DateTime.Now.ToString("H:mm"));
}

此方法计算如果计时器必须在整个小时内对齐时所需的延迟。它仅在频率小于一小时或超过一分钟时有效。

public static TimeSpan ComputeDelay(TimeSpan frequency)
{
    if (frequency > TimeSpan.FromHours(1.0) || 
        frequency < TimeSpan.FromMinutes(1.0))
    {
        throw new ArgumentException(
            "The frequency cannot be more than one hour or less than one minute!");
    }

    return frequency - TimeSpan.FromMinutes(DateTime.Now.Minute % frequency.Minutes);
}

注意:在您的示例中,您以1小时的频率运行45分钟计时器,但您分别在20和30分钟的频率上运行20分钟和30分钟的计时器。我的代码在1小时频率下不能使用45分钟计时器,但它可以在各自频率上使用20,30和45分钟计时器。我不确定你的例子是否错误,但如果没有错,那么我认为你应该能够从这里找出如何处理这个差异。