如何在处理已用事件时阻止计时器?

时间:2009-05-02 16:11:00

标签: c# .net multithreading timer

我有一个计时器,不需要同时处理它的已用事件处理程序。但处理一个Elapsed事件可能会干扰其他事件。我实施了以下解决方案,但感觉不对劲;似乎要么我应该使用不同的计时器,要么在线程空间内使用另一个对象。计时器似乎最合适,因为我确实需要定期检查状态,但有时检查将花费比我的间隔更长的时间。这是解决这个问题的最好方法吗?

// member variable
private static readonly object timerLock = new object();
private bool found = false;


// elsewhere
timer.Interval = TimeSpan.FromSeconds(5).TotalMilliseconds;
timer.Elapsed = Timer_OnElapsed;
timer.Start();


public void Timer_OnElapsed(object sender, ElapsedEventArgs e)
{
  lock(timerLock)
  {
    if (!found)
    {
      found = LookForItWhichMightTakeALongTime();
    }
  }
}

5 个答案:

答案 0 :(得分:14)

您可以将AutoReset设置为false,然后在完成处理后显式重置计时器。当然,你如何处理它实际上取决于你期望计时器如何运作。这样做会使你的计时器偏离实际的指定间隔(如停止和重新启动)。您的机制将允许触发和处理每个间隔,但它可能会导致积压的未处理事件,这些事件现在在接近计时器到期时处理,导致处理程序被调用。

timer.Interval = TimeSpan.FromSeconds(5).TotalMilliseconds;
timer.Elapsed += Timer_OnElapsed;
timer.AutoReset = false;
timer.Start();


public void Timer_OnElapsed(object sender, ElapsedEventArgs e)
{
    if (!found)
    {
      found = LookForItWhichMightTakeALongTime();
    }
    timer.Start();
}

答案 1 :(得分:8)

我通常在处理它时停止计时器,输入一个try / finally块,并在完成时恢复计时器。

答案 2 :(得分:1)

如果LookForItWhichMightTakeALongTime()需要花费很长时间,我建议不要使用System.Windows.Forms.Timer,因为这样做会锁定您的UI线程,并且用户可能会认为它已冻结您的应用程序。

您可以使用的是BackgroundWorker(如果需要,还可以使用Timer。)

public class MyForm : Form
{
  private BackgroundWorker backgroundWorker = new BackgroundWorker();

  public MyForm()
  {
    InitializeComponents();
    backgroundWorker.DoWork += backgroundWorker_DoWork;
    backgroundWorker.RunWorkerCompleted +=
                                backgroundWorker_RunWorkerCompleted;
    backgroundWorker.RunWorkerAsync();
  }

  private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
  {
    e.Result = LookForItWhichMightTakeALongTime();
  }

  private void backgroundWorker_RunWorkerCompleted(object sender,
                                             RunWorkerCompletedEventArgs e)
  {
    found = e.Result as MyClass;
  }
}

您可以随时随地拨打RunWorkerAsync(),如果您愿意,也可以从Timer拨打BackgroundWorker。并且确保检查RunWorkerAsync()是否已经运行,因为在private void timer_Tick(object sender, EventArgs e) { if (!backgroundWorker.IsBusy) backgroundWorker.RunWorkerAsync(); } 运行时会调用异常。

{{1}}

答案 3 :(得分:0)

timer.enabled = false

timer.stop();

timer.enabled = true

timer.start();

答案 4 :(得分:-1)

我像这样使用System.Threading.Timer

 class Class1
    {
        static Timer timer = new Timer(DoSomething,null,TimeSpan.FromMinutes(1),TimeSpan.FromMinutes(1));

        private static void DoSomething(object state)
        {
            timer = null; // stop timer

            // do some long stuff here

            timer = new Timer(DoSomething, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
        }



    }