在Compact Framework中使用System.Threading.Timer

时间:2013-06-10 23:47:11

标签: timer compact-framework

我在CF项目(Windows Embedded CE 6.0),VS2005 C#,.NET 2.0中使用System.Threading.Timer。 这个计时器是理想的,因为这样使用时不可能重入:

    private System.Threading.Timer mainTimer;

    private void MainForm_Load(object sender, EventArgs e)
    {
        // other initializations
        mainTimer = new System.Threading.Timer(new TimerCallback(timerMain_Tick),
                null, 100, Timeout.Infinite);
    }

也就是说,使用dueTime参数但不使用句点。只要句点为Timeout.Infinite,计时器将仅触发一次。通过检查表单的InvokeRequired属性使计时器成为线程安全的。请注意检查null。这与我的问题有关,我很快就会这样做。

    private void timerMain_Tick(object stateInfo)
    {
        if (mainTimer != null)
        {
            if (this.InvokeRequired)
            {
                this.Invoke((ThreadStart)delegate
                {
                    TimerProcess();
                });
            }
            else
            {
                TimerProcess();
            }
        }
    }

计时器必须在退出前重新启动。

    private void TimerProcess()
    {
        try
        {
                // do work here
        }
        finally
        {
            // retrigger
            mainTimer.Change(mainTimerInterval, Timeout.Infinite);
        }
    }

我遇到的问题是优雅地阻止了这件事。

    private void MainForm_Closing(object sender, CancelEventArgs e)
    {
        // shut down timer
        mainTimer.Change(Timeout.Infinite, Timeout.Infinite);
        mainTimer.Dispose();
        mainTimer = null;
    }

在10中大约3次,计时器仍会触发,我收到一个Object Disposed错误。计时器代码试图在检查null之后调用计时器方法。 我怀疑计时器触发,并且在表单关闭时它的线程被挂起。我尝试了一个状态机枚举:

正常运行状态

Form_Closing设置Stopping状态并在Thread.Sleep()循环中等待Stopped状态

计时器看到停止并设置停止状态(而不是重新触发自身)

我遇到的问题是,计时器线程不会抢占表单关闭方法,因此卡在无限循环中。 如何解决这个问题?请注意,在CF中,没有Dispose(WaitHandle)方法。

2 个答案:

答案 0 :(得分:3)

有趣的问题。 Compact Framework中的Timer似乎没有很多选项。

我不确定您的特定代码是如何工作的,因此添加一个静态布尔值可能会或可能不会解决您的问题。

以下是我更改代码以接受timerOK值的方法。如果这不能解决您的问题,它可以为您提供如何处理此问题的想法。

private static bool timerOK;
private static long mainTimerInterval = 200;
private System.Threading.Timer mainTimer;

private void MainForm_Load(object sender, EventArgs e) {
  timerOK = true;
  mainTimer = new System.Threading.Timer(new TimerCallback(timerMain_Tick), null, 100, Timeout.Infinite);
}

private void MainForm_Closing(object sender, CancelEventArgs e) {
  timerOK = false;
  mainTimer.Change(Timeout.Infinite, Timeout.Infinite);
  mainTimer.Dispose();
  mainTimer = null;
}

private void timerMain_Tick(object stateInfo) {
  if (timerOK && (mainTimer != null)) {
    if (this.InvokeRequired) {
      this.Invoke((ThreadStart)delegate {
        TimerProcess();
      });
    } else {
      TimerProcess();
    }
  }
}

private void TimerProcess() {
  if (!timerOK) return;
  try {
    // do work here
  } finally {
    // retrigger
    mainTimer.Change(mainTimerInterval, Timeout.Infinite);
  }
}

答案 1 :(得分:1)

我使用MVP所以我的布局有点不同,但基本上我有两个相同的问题要解决:

  1. 在处理方法中的目标处理后停止计时器触发
  2. 在处理期间停止计时器点火
  3. 第一个很容易修复,因为pwrgreg007显示在上面,只是关闭并在你关闭'关闭时将计时器归零。进程(在处理表单目标之前),然后在计时器处理事件开始时进行空检查。

    第二个问题有点棘手,即使计时器(和你的表单)在处理循环开始时运行,没有什么能阻止它在进程中途停止,因为它在不同的线程上运行。为了防止这种情况,我创建了一个在定时器执行和定时器关闭期间使用的锁。

    //simplified presenter
    public class Presenter
    {
        private const int REFRESH_TIME_MILLISECONDS = 5000;
        private view _view;
        private Timer _timer;
        private object _timerLock = new object();   
    
        //CTOR
        public Presenter()
        {   
            _view = new View();
    
            Startup();
        }
    
        //spin up presenter
        public void Startup(){
    
            //bind view shutdown event
            _view.ViewClosing += Shutdown;
    
            //start timer
            _timer = new Timer(DoTimerStuff, null, REFRESH_TIME_MILLISECONDS, Timeout.Infinite);
        }
    
        //spin down presenter
        public void Shutdown()
        {
            //wait for any DoTimerStuff locks to expire
            lock (_timerLock)
            {
                //stop the timer
                _timer.Change(Timeout.Infinite, Timeout.Infinite);
                _timer.Dispose();
                _timer = null;                
            }
    
            //close the view
            _view.Shutdown();
        }
    
        //timer tick
        private void DoTimerStuff(object state)
        {
            //grab a lock so we can ensure the timer doesn't get shutdown mid way through
            lock (_timerLock)
            {
                //make sure the timer isn't shutdown (from form closing)
                if (_timer == null) return;
    
                //do your stuff here
                _view.SomeInvokedCheckedProperty = "SomeValue";
                //etc...
    
                //schedule next timer execute (runs every runtime + refresh time)
                _timer.Change(REFRESH_TIME_MILLISECONDS, Timeout.Infinite);
            }
        }
    }
    
    //simplified view
    public class View : Form
    {
    
        //view properties (make sure they are invoke checked)
        public SomeInvokedCheckedProperty {get;set;}
    
        //Bound to ViewClosing
        private void View_Closing(object sender, System.ComponentModel.CancelEventArgs e)
            {
                //stop the view closing itself
                e.Cancel = true;
    
                //tell the presenter to handle closing instead
                if (ViewClosing != null) ViewClosing.Invoke();
            }
    }
    

    那样......

    • 如果DoTimerStuff()有锁并且当前正在运行,计时器将等待关机(暂停表单关闭)
    • 相反,如果定时器关闭有锁定,DoTimerStuff()将等待,并且当它继续时它将正确地看到定时器关闭(并且什么都不做)。