2013-01-24 2 views
2

데이터베이스에서 많은 양의 데이터를 수집하는 Backgroundworker가 있습니다. 스레드에 시간 초과 제한을 설정하여 프로세스가 취소 된 정해진 시간 후에 결과를 반환하지 않도록하고 싶습니다.타이머 경과 이벤트가 모든 작업을 수행하지 않습니다.

BackgroundWorker를 시작하는 것과 동시에 주 스레드에서 타이머를 시작합니다.

의도적으로 BGW를 잠자기 상태로 만들면 타이머가 경과하고 .Elapsed 이벤트가 호출됩니다. 그런 다음 Background 작업자를 취소하지만 GUI에서 상태 표시 줄을 업데이트하고 MessageBox를 표시하는 완료 작업을 성공적으로 완료하지 못합니다. 나는 왜 이해하지 못한다. 아무도 도와 줄 수 있니?

시간 초과 및 절전이 의도적으로 테스트를 위해 설정됩니다.

 /// <summary> 
     /// loads Assets by group ID 
     /// Populates Grid on asset listing page 
     /// </summary> 
     /// <param name="groupId"></param> 
     /// <param name="user"></param> 
     internal void PopulateGridAssetsByGroup(int groupId, User user) 
     { 
      //update statusbar 
      AfMainWindow.MainWindow.UpdateStatusBar("Loading Assets..."); 

      //setup BG worker 
      populateGridAssetsWorker = new BackgroundWorker {WorkerSupportsCancellation = true, WorkerReportsProgress = false}; 
      populateGridAssetsWorker.DoWork += populateGridAssetsWorker_DoWork; 
      populateGridAssetsWorker.RunWorkerCompleted += populateGridAssetsWorker_RunWorkerCompleted; 

      //setup timer which will cancel the background worker if it runs too long 
      cancelTimer = new Timer {Interval = 2000, Enabled = true, AutoReset = false}; 
      cancelTimer.Elapsed += cancelTimer_Elapsed; 
      cancelTimer.Start(); 

      populateGridAssetsWorker.RunWorkerAsync(groupId); //start bg worker 
     } 


     void cancelTimer_Elapsed(object sender, ElapsedEventArgs e) 
     { 
      populateGridAssetsWorker.CancelAsync(); 
      cancelTimer.Stop(); 

      AfMainWindow.MainWindow.UpdateStatusBar("Could not load assets, timeout error"); 

      MessageBox.Show("Operation Timed Out\n\nThe Server did not respond quick enough, please try again", 
          "Timeout", MessageBoxButton.OK, MessageBoxImage.Exclamation, MessageBoxResult.OK); 

      AfMainWindow.MainWindow.Busy.IsBusy = false; 

     } 

     /// <summary> 
     /// when bg worker complete, update the AssetGrid on Asset Listing Page with results 
     /// </summary> 
     /// <param name="sender"></param> 
     /// <param name="e"></param> 
     void populateGridAssetsWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 

      cancelTimer.Stop(); 

      //my thread complete processing 

     }   
     /// <summary> 
     /// Perform the DB query and collect results for asset listing 
     /// </summary> 
     /// <param name="sender"></param> 
     /// <param name="e"></param> 
     void populateGridAssetsWorker_DoWork(object sender, DoWorkEventArgs e) 
     { 
      var assetListByGroup = new List<AssetLinked>(); 

      Thread.Sleep(5000); 

      if (populateGridAssetsWorker.CancellationPending) 
      { 
       return; 
      } 

      try 
      { 

       //My SQL actions 

      if (populateGridAssetsWorker.CancellationPending) 
      { 
       return; 
      } 
      } 
      catch (Exception ex) 
      { 
       Globals.AFWideSettings.GeneralErrorMessage(ex.Message); 
      } 
     } 
+0

아래 투표 결과는 정확히 무엇입니까? – Damo

+1

+1은 downvote를 무효화합니다. 나에게 합리적인 질문처럼 보입니다. – PeteH

+0

이것은 중단 점의 주요 후보자처럼 보입니다. 아마도 이미 이것을 했나요? 그래서 당신은 MessageBox.Show .... 히트하지만 메시지 상자를 얻지 않는다고 말하고 있습니까? – PeteH

답변

2

난 당신이 다른 스레드에서 GUI를 업데이트 할 때 자동으로 당신의 cancelTimer_Elapsed 방법은 충돌 가정 . 백그라운드 스레드에서 발생하는 예외는 Visual Studio에서 디버깅하지 않고도 모든 예외가 발생하지 않도록 찾기가 어렵습니다. 메뉴에서 Debug > Exceptions을 설정하고 모든 CLR 예외를 검사 할 수 있습니다. 또는 try 블록에 메서드 본문을 래핑하고 catch 블록에 중단 점을 넣을 수 있습니다.

void cancelTimer_Elapsed(object sender, ElapsedEventArgs e) 
{ 
    try 
    { 
     populateGridAssetsWorker.CancelAsync(); 
     cancelTimer.Stop(); 

     AfMainWindow.MainWindow.UpdateStatusBar("Could not load assets, timeout error"); 

     MessageBox.Show("Operation Timed Out\n\nThe Server did not respond quick enough, please try again", 
         "Timeout", MessageBoxButton.OK, MessageBoxImage.Exclamation, MessageBoxResult.OK); 

     AfMainWindow.MainWindow.Busy.IsBusy = false; 
    } 
    catch(Exception ex) 
    { 
     int breakpoint = 42; 
    } 
} 

필자는 결코 그런 것은 아니지만 필자의 의견으로는 가치가있다.

+0

아. 이것을 수행하고 디버그 출력을 캐치에 추가했습니다. 우리는 "호출 스레드가 다른 스레드가 소유하고 있기 때문에이 개체에 액세스 할 수 없습니다." 하지만 이벤트가 주 스레드에 확실하게 있습니까? – Damo

+1

오 ... http://stackoverflow.com/questions/1435876/do-c-sharp-timers-elapse-on-a-separate-thread – Damo

+0

위대한, 그래서 당신은 문제를 발견했습니다. 'Timer'는 실제로 더 많은 (ThreadPool) 쓰레드를 사용합니다 - 하나는 타이머 자체이고 나머지 하나는'Elapsed' 핸들러입니다. 따라서 이벤트가 메인 스레드에서 발생하지 않으면 GUI 관련 코드를 메인 스레드로 다시 이동시키는 메커니즘이 필요합니다. –

관련 문제