2013-06-10 2 views
2

CF 프로젝트 (Windows Embedded CE 6.0), VS2005 C#, .NET 2.0에서 System.Threading.Timer를 사용하고 있습니다. 다음과 같이 사용 재진입의 가능성이 없기 때문에이 타이머가 요구된다Compact Framework에서 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; 
    } 

어쨌든 타이머가 3 회 발생하고 Object Disposed 오류가 발생합니다. 타이머 코드가 null 확인 후 타이머 메서드를 호출하려고합니다. 타이머가 작동하고 폼이 닫히는 동안 스레드가 일시 중단 된 것으로 의심됩니다. 나는 상태 머신 열거 시도 :

정지 상태에 대한 Thread.sleep를() 루프 상태와 대기를 중지

Form_Closing 세트를 실행 정상 상태

타이머보고 중지 및 세트 상태를 중지됨 (보다는 다시 트리거 자체)

문제 타이머 스레드가 양식 닫기 메서드를 선점하지 않을 것이므로 문제가 발생하지 않으므로 무한 루프에 걸릴 수 있습니다. 이 문제를 해결하는 방법? CF에는 Dispose (WaitHandle) 메서드가 없습니다.

+0

ObjectDisposedException을 처리하고 무시하는 것이 좋습니다. 상관 있니? 나는 전에 모호한 경우에 그것을 했어. – Alan

+0

이것이 결국 내가 한 일이다. 시도하지는 않았지만 아래 @ jp2code의 대답도 실행 가능해 보입니다. 수동으로 타이머를 시작하려고했습니다 : mainTimer.Change (0, Timeout.Infinite); 상태 기계를 '중지됨'상태로 만들지 만 항상 작동하지는 않습니다. 이 객체는 올바르게 동작하지 않습니다. – pwrgreg007

답변

2

흥미로운 문제. Compact Framework에서 Timer에는 많은 옵션이없는 것 같습니다.

특정 코드가 어떻게 작동하는지 잘 모르므로 하나의 정적 부울 값을 추가하면 문제가 해결 될 수도 있고 해결되지 않을 수도 있습니다.

코드를 변경하여 timerOK 값을 허용하는 방법은 다음과 같습니다. 이렇게해도 문제가 해결되지 않으면 문제 해결 방법에 대한 아이디어를 얻을 수 있습니다. 내가 MVP를 사용하고

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. 는 처리 방법에 목표 후 타이머 발사 중지
  2. 은 F 전에 (언젠가 당신의 '폐쇄'과정에서 pwrgreg007 상기와 같이

먼저 하나가 쉽게 고정 처리 도중 바로 종료 및 널 (null) 타이머를 타이머 발사 중지 orm 대상이 삭제됨) 타이머 처리 이벤트가 시작될 때 null 확인을 수행하십시오.

두 번째 문제는 처리 루프가 시작될 때 타이머 (및 양식)가 실행중인 경우에도 조금 까다 롭습니다. 프로세스가 다른 스레드에서 실행 중일 때 중간 단계에서 종료되는 것을 막을 수있는 방법은 없습니다. 이를 방지하기 위해 타이머 실행과 타이머 종료 중에 잠금을 사용했습니다.

//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()는 타이머 경우 대기 shutdown은 lock을 가지고 있고 계속 될 때 타이머가 shutdown 된 것을 정확하게 볼 것입니다.