2011-12-18 111 views
2

我正在使用BackgroundWorker線程調用一個小例程,它接收來自MSMQ的消息,一旦消息到達MSMQ隊列(消息到達msmq,每隔5秒)它涉及到我的應用程序這是使用BackgroundWorker線程。以下是我的Win Form類。我是線程的新手,所以如果我做錯了什麼,請請諒解BackgroundWorker線程不會停止winforms c#

問題:我的應用程序是MDI應用程序,當我第一次執行我的應用程序時,它工作得很好,一收到MSMQ消息,隊列,這是每5秒,但是當我關閉這個表單時,它是一個子表單,它關閉的很好,但是在打開同樣的表單後,我正在接收來自MSMQ的消息,並持續了10秒的達賴,所以這意味着我正在搞亂一些東西在後臺工作線程中,我試圖取消這個後臺工作線程,但是我失敗了,無法正確地執行或終止線程。請幫助並分享您的體驗。下面是我的表單代碼。

public partial class FrmBooking : BookingManager.Core.BaseForm.BaseForm 
{ 
    internal const string queName = @"messageServer\private$\Response"; 
    private Int32 counter = 0; 
    BackgroundWorker backgroundWorker1 = new BackgroundWorker(); 


    public FrmBooking() 
    { 
     InitializeComponent(); 
     backgroundWorker1.WorkerReportsProgress = true; 
     backgroundWorker1.WorkerSupportsCancellation = true; 
     backgroundWorker1.RunWorkerCompleted+=new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted); 
     backgroundWorker1.ProgressChanged+=new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged); 
     backgroundWorker1.DoWork+=new DoWorkEventHandler(backgroundWorker1_DoWork); 

    }   

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
    { 
     BackgroundWorker bgWorker = sender as BackgroundWorker; 

     if (bgWorker.CancellationPending) 
     { 
      e.Cancel = true; 
      return; 
     } 


      try 
      { 

       MessageQueue messageQueue = null; 
       if (MessageQueue.Exists(queName)) 
       { 
        messageQueue = new MessageQueue(queName); 
       } 
       else 
       { 
        MessageQueue.Create(queName); 
       } 

       messageQueue.Formatter = new XmlMessageFormatter(new Type[] { typeof(String) }); 

       System.Messaging.Message msg = messageQueue.Receive(); 



       bgWorker.ReportProgress(100, msg); 

      } 
      catch (Exception ex) { } 


    } 
    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     if (!e.Cancelled) 
     { 
      backgroundWorker1.RunWorkerAsync(); 
     } 


    } 
    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 

     System.Messaging.Message msg = e.UserState as System.Messaging.Message; 

     listBoxControl1.Items.Add(msg.Body.ToString()); 
     counter++; 
     labelControl1.Text = String.Format("Total messages received {0}", counter.ToString()); 
    } 

    private void FrmBooking_Load(object sender, EventArgs e) 
    { 
     backgroundWorker1.RunWorkerAsync(); 

    } 
} 

回答

0

當您關閉表單時,您是否終止工作人員?如果沒有,如果有表單的引用或某個地方的工作人員(事件處理程序?),那麼它將不會得到GCd並停留在附近。當打開第二個實例可能運行兩個後臺工作者....

+0

是的,當我關閉窗體我想說backgroundworker.cancelasync(),但此行的事幫助。你是對的參考是一些如何活着,不知道我怎麼能阻止它...仍然嘗試 – Shax 2011-12-18 09:44:23

1

你這裏有兩種選擇:

1)在窗體的Closing事件,呼籲backgroundWorker1。 CancelAsync()。

2)更好的方法是完全刪除你的後臺工作者,並使用MessageQueue的本地異步處理機制。添加ReceivedCompleted事件處理程序後,您可以使用BeginReceive方法啓動隊列請求,然後在完成的事件處理程序中處理消息並重新啓動請求。

問題是,如果您發出接收請求,它將阻塞後臺工作線程,直到隊列中收到一條消息,並且CancelAsync只會請求後臺工作者停止,它不會取消接收請求。

例如(更新):

public partial class FrmBooking : BookingManager.Core.BaseForm.BaseForm 
{ 
    public FrmBooking() 
    { 
     InitializeComponent(); 

     this.FormClosing += new FormClosingEventHandler(FrmBooking_FormClosing); 
    } 

    internal const string queName = @"messageServer\private$\Response"; 
    private Int32 counter = 0; 
    private MessageQueue messageQueue = null; 

    private bool formIsClosed = false; 

    private void FrmBooking_Load(object sender, EventArgs e) 
    { 
     StartQueue(); 
    } 

    void FrmBooking_FormClosing(object sender, FormClosingEventArgs e) 
    { 
     // Set the flag to indicate the form is closed 
     formIsClosed = true; 

     // If the messagequeue exists, close it 
     if (messageQueue != null) 
     { 
      messageQueue.Close(); 
     } 
    } 

    private void StartQueue() 
    { 
     if (MessageQueue.Exists(queName)) 
     { 
      messageQueue = new MessageQueue(queName); 
     } 
     else 
     { 
      MessageQueue.Create(queName); 
     } 

     messageQueue.Formatter = new XmlMessageFormatter(new Type[] { typeof(String) }); 

     // Add an event handler for the ReceiveCompleted event. 
     messageQueue.ReceiveCompleted += new ReceiveCompletedEventHandler(MessageReceived); 

     messageQueue.BeginReceive(TimeSpan.FromSeconds(15)); 
    } 

    // Provides an event handler for the ReceiveCompleted event. 
    private void MessageReceived(Object source, ReceiveCompletedEventArgs asyncResult) 
    { 
     if (!this.formIsClosed) 
     { 
      // End the asynchronous receive operation. 
      System.Messaging.Message msg = messageQueue.EndReceive(asyncResult.AsyncResult); 

      // Display the message information on the screen. 
      listBoxControl1.Items.Add(msg.Body.ToString()); 
      counter++; 
      labelControl1.Text = String.Format("Total messages received {0}", counter.ToString()); 

      // Start receiving the next message 
      messageQueue.BeginReceive(TimeSpan.FromSeconds(15)); 
     } 
    } 

} 
+0

是的,這就是我已經叫做CancelAsync(),但沒有幫助。任何其他想法?我知道我可以使用時間跨度,但我不想使用,因爲由於時間的緣故,我可能會遲到讀取一些消息。所以我需要在隊列中讀取消息。 – Shax 2011-12-18 09:46:05

+0

@Shax:我建議重寫代碼以使用上面的方法2,因爲當前的實現會掛起backgroundworker線程,直到隊列中收到新消息。 – 2011-12-18 16:25:18

+0

我試過第二種方法,但同樣的反應,你可以分享一些代碼來實現它,真的很感謝你在這方面的支持。 – Shax 2011-12-18 17:55:54