2011-12-18 132 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