首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C# -如何暂停应用程序直到计时器完成?

C# -如何暂停应用程序直到计时器完成?
EN

Stack Overflow用户
提问于 2016-07-07 19:14:22
回答 2查看 10.4K关注 0票数 0

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

代码语言:javascript
运行
复制
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.......
}

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

代码语言:javascript
运行
复制
private void OnTimedEvent(object obj, ElapsedEventArgs e)
{
    TimerSettings.TimerFinished = true;
}

while循环只是无限循环,直到计时器完成,或者直到一个取消请求被放入。我想保留这个功能,但我不想在等待计时器完成时永远循环。我的计时器可以设置为每隔几天运行一次,因此在这么长时间内循环是没有意义的。

还有别的办法吗?

我知道我能做到:

代码语言:javascript
运行
复制
Thread.Sleep(runDuration.TotalMilliseconds);

然而,这将是阻塞的,我将无法提出取消请求。

编辑:因此,为了详细说明我需要暂停的是什么/为什么需要暂停,这里有一个关于我的应用程序的更详细的解释。基本上,我希望有一个应用程序在一个固定的间隔上执行“工作”。因此,根据下面提供的一个答案,如果我做了这样的事情:

代码语言:javascript
运行
复制
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;
    }
  }
}

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

代码语言:javascript
运行
复制
while (!TimerSettings.TimerFinished && !quitToken.IsCancellationRequested);

这至少起作用了,但如前所述,这可能是暂停线程的资源密集型方法。基本上,我真正需要的是一种阻止线程直到计时器上升的方法。

EDIT2:这是我最后一个使用等待句柄工作的实现.

代码语言:javascript
运行
复制
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; }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-07-07 19:43:59

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

代码语言:javascript
运行
复制
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/en-us/library/system.timers.timer.elapsed(v=vs.110).aspx

在我看来,关于“暂停”,有两个理由要暂停,我不知道是你的原因:

  1. 您希望防止应用程序“完成”执行并正常终止。
  2. 您希望推迟执行其他代码,直到所需的间隔时间已经过去。

如果你的理由是#2,那么这个答案就完成了。

票数 0
EN

Stack Overflow用户

发布于 2016-07-07 19:19:56

首先:“你绝对不需要(!)想‘忙’--等待任何东西!”(坏狗!不要饼干!)

嗯哼..。

这个问题的一个实际解决方案是对信号量(或任何其他合适的互斥对象.)执行定时等待,而不是使用实际的计时器。如果你需要在等待完成之前摆脱它,只需在等待的东西上闪过。

您目前的“解决方案”的关键问题是,它将使进程100%的CPU利用率,完全浪费。从来没有那样做过!

票数 -3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38253572

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档