2010-03-11 59 views
0

JI在Visual Studio 2008中編寫了.NET C#Windows窗體應用程序,它使用信號量在按下「開始」按鈕時將多個作業作爲線程運行。Windows窗體在運行線程時掛起

遇到一個問題,表單在運行40分鐘或更長時間後進入逗號。日誌文件表明當前作業完成,它從列表中選擇一個新作業,並在那裏掛起。

我注意到當這種情況發生時,Windows窗體變得沒有響應。該表單正在其自己的線程中運行。

這是我使用的代碼的一個示例:

protected void ProcessJobsWithStatus (Status status) 
     { 
int maxJobThreads = Convert.ToInt32(ConfigurationManager.AppSettings["MaxJobThreads"]); 
      Semaphore semaphore = new Semaphore(maxJobThreads, maxJobThreads); // Available=3; Capacity=3 


      int threadTimeOut = Convert.ToInt32(ConfigurationManager.AppSettings["ThreadSemaphoreWait"]);//in Seconds 
      //gets a list of jobs from a DB Query. 
List<Job> jobList = jobQueue.GetJobsWithStatus(status); 
      //we need to create a list of threads to check if they all have stopped. 
      List<Thread> threadList = new List<Thread>(); 
      if (jobList.Count > 0) 
      { 
       foreach (Job job in jobList) 
       { 
        logger.DebugFormat("Waiting green light for JobId: [{0}]", job.JobId.ToString()); 
        if (!semaphore.WaitOne(threadTimeOut * 1000)) 
        { 
         logger.ErrorFormat("Semaphore Timeout. A thread did NOT complete in time[{0} seconds]. JobId: [{1}] will start", threadTimeOut, job.JobId.ToString()); 

        } 

        logger.DebugFormat("Acquired green light for JobId: [{0}]", job.JobId.ToString()); 
        // Only N threads can get here at once  
        job.semaphore = semaphore; 
        ThreadStart threadStart = new ThreadStart(job.Process); 

        Thread thread = new Thread(threadStart); 
        thread.Name = job.JobId.ToString(); 
        threadList.Add(thread); 
        thread.Start(); 


       } 

       logger.Info("Waiting for all threads to complete"); 

       //check that all threads have completed. 
       foreach (Thread thread in threadList) 
       { 
        logger.DebugFormat("About to join thread(jobId): {0}", thread.Name); 
        if (!thread.Join(threadTimeOut * 1000)) 
        { 
         logger.ErrorFormat("Thread did NOT complete in time[{0} seconds]. JobId: [{1}]", threadTimeOut, thread.Name); 
        } 
        else { 
         logger.DebugFormat("Thread did complete in time. JobId: [{0}]", thread.Name); 
        } 
       }     

      } 

      logger.InfoFormat("Finished Processing Jobs in Queue with status [{0}]...", status); 

} 

//形式方法

public void Process() 
     { 
      try 
      { 

       //sets the status, DateTimeStarted, and the processId 
       this.UpdateStatus(Status.InProgress); 

       //do something 

       logger.Debug("Updating Status to [Completed]"); 

       //hits, status,DateFinished 
       this.UpdateStatus(Status.Completed); 

      } 
      catch (Exception e) 
      { 
       logger.Error("Exception: " + e.Message); 
       this.UpdateStatus(Status.Error); 

      } 
      finally { 
       logger.Debug("Relasing semaphore"); 
       semaphore.Release(); 
      } 

我試圖

private void button1_Click(object sender, EventArgs e) 
     { 
      buttonStop.Enabled = true; 
      buttonStart.Enabled = false; 

      ThreadStart threadStart = new ThreadStart(DoWork); 
      workerThread = new Thread(threadStart); 

      serviceStarted = true; 
      workerThread.Start(); 



     } 

private void DoWork() 
     { 
      EmailAlert emailAlert = new EmailAlert(); 
      // start an endless loop; loop will abort only when "serviceStarted" flag = false 
      while (serviceStarted) 
      { 
       emailAlert.ProcessJobsWithStatus(0); 

       // yield 
       if (serviceStarted) 
       { 
        Thread.Sleep(new TimeSpan(0, 0, 1)); 
       } 
      } 

      // time to end the thread 
      Thread.CurrentThread.Abort(); 
     } 

//job.process()記錄我可以將文件記錄到文件中以檢測問題發生的位置,但到目前爲止,我還無法確定發生了什麼。失去對Windows窗體的控制使我認爲這與處理作業無關。有任何想法嗎?

解決方案:使用RedGate ANTS進行性能分析正在產生問題。直接運行時不會發生。

+0

嘗試運行Visual Studio並在掛起時插入代碼(僅使用暫停按鈕)。然後使用線程窗口來檢查所有等待的線程。 – Grzenio 2010-03-11 16:43:48

回答

3

我看到的第一件事是你的Thread.CurrentThread.Abort()電話。這是不必要的。讓函數退出並且線程將優雅地關閉。

我注意到的第二件事是,即使獲取信號量發生超時,線程也會被創建。由於線程過多,您的表單可能會掛起。

logger.DebugFormat("Waiting green light for JobId: [{0}]", job.JobId.ToString()); 
if (!semaphore.WaitOne(threadTimeOut * 1000)) 
{ 
    logger.ErrorFormat("Semaphore Timeout. A thread did NOT complete in time[{0} seconds]. JobId: [{1}] will start", threadTimeOut, job.JobId.ToString()); 
    // Should have exit here. 
} 
logger.DebugFormat("Acquired green light for JobId: [{0}]", job.JobId.ToString()); 

第三件事是你的工作線程呼喚它只是在工作循環的每個作業創建線程功能。如果作業沒有完成(假設這會導致作業從隊列中刪除,因爲我沒有在任何地方看到該代碼)。在DoWork從睡眠狀態喚醒之前,它將遍歷相同的作業並嘗試創建另一個作業爲它的線程。

+0

對於我在日誌中可以看到的線程正在終止信號量的時間。在執行應用程序的過程中,總線程數量保持不變。 – 2010-03-11 16:46:29

+0

你如何確定線程數? – 2010-03-11 16:54:44

+0

如果您使用的ThreadList是ProcessJobsWithStatus的本地對象,它將會持續30,但實際計數會更高。檢查任務管理器,看看我的意思。 – 2010-03-11 16:56:34

相關問題