我有一个计时器,不需要同时处理它的已用事件处理程序。但处理一个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();
    }
  }
}
有帮助吗?

解决方案

您可以将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();
}

其他提示

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

如果 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();
}
timer.enabled = false

timer.stop();

timer.enabled = true

timer.start();

我像这样使用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));
        }



    }
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top