C#-如何暂停应用程序,直到计时器完成? [英] C# - How to pause application until timer is finished?

查看:166
本文介绍了C#-如何暂停应用程序,直到计时器完成?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个需要等待特定时间的应用程序,但是如果需要,我还需要能够取消当前操作.我有以下代码:

I have an application that I need to have wait a specific amount of time, but I also need to be able to cancel the current operation if needed. I have the following code:

private void waitTimer(int days)
{
    TimeSpan waitTime = TimeSpan.FromDays(days);
    System.Timers.Timer timer = new System.Timers.Timer(waitTime.TotalMilliseconds);   // Wait for some number of milliseconds
    timer.Enabled = true;
    timer.Start();
    timer.Elapsed += new ElapsedEventHandler(OnTimedEvent); // Subscribe to event handler

    while (!TimerSettings.TimerFinished && !quitToken.IsCancellationRequested);  // Loop forever untill timer is finished or operation is cancled. 

    timer.Elapsed -= new ElapsedEventHandler(OnTimedEvent); // Unsubscribe

    DoWork(); // Do work when timer finishes.......
}

以下是计时器完成事件的事件处理程序:

Below is the event handler for the timer finished event:

private void OnTimedEvent(object obj, ElapsedEventArgs e)
{
    TimerSettings.TimerFinished = true;
}

while循环无限循环,直到定时器完成或发出取消请求为止.我想保留此功能,但我不想在等待定时器完成时永远循环.我的计时器可以设置为每隔几天运行一次,因此循环这么长时间没有意义.

The while loop just loops infinitely until the timer is finished or until a cancelation request is put in. I want to retain this functionality but I would rather not loop forever while waiting for the timer to finish. My timer can be set to run on an interval of multiple days so it doesn't make sense to loop for so long.

还有另一种方法吗?

我知道我可以做到:

Thread.Sleep(runDuration.TotalMilliseconds);

但是,这将阻止您执行取消请求.

However, this would be blocking and I would not be able to put in a cancelation request.

因此,为了详细说明我需要在此处暂停的原因/原因,是我的应用程序的更详细说明.基本上,我希望有一个定期执行工作"的应用程序.因此,根据以下提供的答案之一,如果我做了这样的事情:

So in order to elaborate on what/why I need to pause here is a more detailed explination of my application. Basically I want to have an application that performs "work" on a regular interval. So based on one of the answers provided below, if I did something like this:

class Program
{
    // Do something in this method forever on a regular interval 
    //(could be every 5min or maybe every 5days, it's up to the user)
    static void Main(string[] args)
    {
        while(true)
        {
          if(args?.Length > 0)
              waitTimer(args[0]);
          else 
              wiatTimer(TimeSpan.FromDays(1).TotalSeconds); // Default to one day interval
        }             
    }

private void waitTimer(int numIntervals)
{
    this.ElapsedIntervals = 0;
    this.IntervalsRequired = numIntervals;
    this.timer = new System.Timers.Timer(1000);   // raise the elapsed event every second
    timer.Elapsed += new ElapsedEventHandler(OnTimedEvent); // Subscribe to event handler
    //timer.Enabled = true; timer.Start() does this for you, don't do this
    timer.Start();
    //thats all here
}

 private void OnTimedEvent(object obj, ElapsedEventArgs e)
 {
    this.ElapsedIntervals += 1;
    if(this.CancelRequested)
    {
       this.ElapsedIntervals = 0;
       this.timer.Stop();
       return;
    }
    if(this.ElapsedIntervals >= this.IntervalsRequired)
    {
       this.ElapsedIntervals = 0;
       this.timer.Stop();
       DoWork();   // This is where my work gets done.......
      return;
    }
  }
}

然后我的服务/控制台应用程序将启动并进入无限循环,该循环仅整天设置计时器.以前,我实际上是在以下位置停止执行任何其他代码:

Then my service/console app would start and go into an infinite loop that just sets timers all day long. Previously, I was actually halting execution of any other code at:

while (!TimerSettings.TimerFinished && !quitToken.IsCancellationRequested);

至少有效的方法,但是如前所述,可能是暂停线程的资源密集型方法.基本上,我真正需要的是一种阻塞线程直到计时器到了的方法.

Which at least worked, but as mentioned, can possibly be resource intensive way to pause a thread. Basically what I really need is a way to block my thread untill the timer is up.

这是我的最终实现,似乎使用等待句柄对我有用...

This is my final implementation that seems to work for me using a wait handle...

class TimerClass
{
    /// <summary>
    /// Initialize new timer. To set timer duration,
    /// either set the "IntervalMinutes" app config 
    /// parameter, or pass in the duration timespan.
    /// </summary>
    /// <param name="time"></param>
    internal bool StartTimer(CancellationToken quitToken, TimeSpan? duration = null)
    {
        TimeSpan runDuration = new TimeSpan();
        runDuration = duration == null ? GetTimerSpan() : default(TimeSpan);

        if (runDuration != default(TimeSpan))
        {
            WaitTimer(runDuration); // Waits for the runduration to pass
        }
        return true;
    }

    /// <summary>
    /// Get duration to run the timer for.
    /// </summary>
    internal TimeSpan GetTimerSpan()
    {
        TimerSettings.Mode = App.Settings.Mode;
        DateTime scheduledTime = new DateTime();

        switch (TimerSettings.Mode)
        {
            case "Daily":
                scheduledTime = DateTime.ParseExact(App.Settings.ScheduledTime, "HH:mm:ss", CultureInfo.InvariantCulture);
                if (scheduledTime > DateTime.Now)
                    TimerSettings.TimerInterval = scheduledTime - DateTime.Now;
                else
                    TimerSettings.TimerInterval = (scheduledTime + TimeSpan.FromDays(1)) - DateTime.Now;
                break;
            case "Interval":
                double IntervalMin = double.TryParse(App.Settings.PollingIntervalMinutes, out IntervalMin) ? IntervalMin : 15.00;
                int IntervalSec = Convert.ToInt32(Math.Round(60 * IntervalMin));
                TimeSpan RunInterval = new TimeSpan(0, 0, IntervalSec);
                TimerSettings.TimerInterval = RunInterval;
                break;
            case "Manual":
                TimerSettings.TimerInterval = TimeSpan.FromMilliseconds(0);
                break;
            default:
                TimerSettings.TimerInterval = (DateTime.Today + TimeSpan.FromDays(1)) - DateTime.Now;
                break;
        }
        return TimerSettings.TimerInterval;
    }

    /// <summary>
    /// Event handler for each timer tick.
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="e"></param>
    private void OnTimedEvent(object obj, ElapsedEventArgs e)
    {
        ElapsedIntervals += 1;
        if (CancelRequested.IsCancellationRequested) // If the application was cancled
        {
            ElapsedIntervals = 0;
            timer.Stop();
            WaitHandle.Set();
            return;
        }
        if (ElapsedIntervals >= IntervalsRequired) // If time is up
        {
            ElapsedIntervals = 0;
            timer.Stop();
            WaitHandle.Set();
            return;
        }
    }

    /// <summary>
    /// Timer method to wait for a
    /// specified duration to pass. 
    /// </summary>
    /// <param name="span"></param>
    private void WaitTimer(TimeSpan span)
    {
        WaitHandle = new AutoResetEvent(false);
        int tickDuration = 1000;  // Number of milliseconds for each tick
        IntervalsRequired = Convert.ToInt64(span.TotalMilliseconds / (tickDuration > 0 ? tickDuration : 0.01));
        timer = new System.Timers.Timer(tickDuration);          // Raise the elapsed event every tick
        timer.Elapsed += new ElapsedEventHandler(OnTimedEvent); // Subscribe to event handler for when each tick is complete
        timer.Start();           // Start ticking
        WaitHandle.WaitOne();    // Halt the main thread untill span is reached
    }


    // Timer parameters: 
    private static long ElapsedIntervals { get; set; }
    private static long IntervalsRequired { get; set; }
    private static System.Timers.Timer timer { get; set; }
    private static CancellationToken CancelRequested { get; set; }
    private static string Mode { get; set; }
    private static TimeSpan TimerInterval { get; set; }
    private static EventWaitHandle WaitHandle { get; set; }
}

internal static class TimerSettings
{
    internal static string Mode { get; set; }
    internal static TimeSpan TimerInterval { get; set; }
}

推荐答案

您应该查看Timer.Elapsed事件文档. AutoReset属性设置为true(默认设置)时,每次间隔时间过后,都会重复引发此事件.我将保留您自己已计数的间隔时间的计数,并将其与此事件处理程序中所需的经过时间间隔进行比较,以检查是否该停止计时器了.在这种情况下,您还可以处理取消.如果您的计时器完成了所需的间隔数,则可以从该事件处理程序中调用doWork函数.

You should look at the Timer.Elapsed Event documentation. This event will be raised repeatedly every time the interval elapses while the AutoReset property is set to true (which is default). I would keep your own count of how many intervals have elapsed and compare it to the required elapsed intervals in this event handler to check whether it is time to stop the timer. In that event, you can also handle cancellation. If your timer finishes its required number of intervals, you may call your doWork function from that event handler.

private void waitTimer(int numIntervals)
{
    this.ElapsedIntervals = 0;
    this.IntervalsRequired = numIntervals;
    this.timer = new System.Timers.Timer(1000);   // raise the elapsed event every second
    timer.Elapsed += new ElapsedEventHandler(OnTimedEvent); // Subscribe to event handler
    //timer.Enabled = true; timer.Start() does this for you, don't do this
    timer.Start();
    //thats all here
}

private void OnTimedEvent(object obj, ElapsedEventArgs e)
{
    this.ElapsedIntervals += 1;
    if(this.CancelRequested)
    {
        this.ElapsedIntervals = 0;
        this.timer.Stop();
        return;
    }
    if(this.ElapsedIntervals >= this.IntervalsRequired)
    {
       this.ElapsedIntervals = 0;
       this.timer.Stop();
       DoWork();
       return;
    }
}

https://msdn.microsoft.com/zh-CN/library/system.timers.timer.elapsed(v=vs.110).aspx

就我看来,关于暂停",有两个原因需要暂停,但我不确定是您的哪个原因:

As I see it, with regards to "pausing", there are two reasons to want to pause and I am unsure which reason is yours:

  1. 您要防止应用程序完成"执行并正常终止.
  2. 您要在执行所需的时间间隔之前推迟执行其他代码

如果您的原因是#2,那么答案是完整的.

If your reason is #2, then this answer is complete.

这篇关于C#-如何暂停应用程序,直到计时器完成?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆