【问题标题】:BackgroundWorker thread is not stopping winforms c#BackgroundWorker 线程没有停止 winforms c#
【发布时间】:2011-12-18 00:45:37
【问题描述】:

我正在使用BackgroundWorker 线程调用一个小例程,该例程在消息到达 MSMQ 队列后立即从 MSMQ 接收消息(消息每 5 秒到达 msmq)它来到我使用 @987654322 的应用程序@ 线。下面是我的 Win Form 课程。我是线程新手,所以如果我做错了什么请道歉

问题:我的应用程序是 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();

    }
}

【问题讨论】:

    标签: c# winforms multithreading backgroundworker


    【解决方案1】:

    你有两个选择:

    1) 在Form的Closing事件中,调用backgroundWorker1.CancelAsync()。

    2) 更好的方法是完全删除您的后台工作人员并为此使用 MessageQueue 的本机异步处理机制。您可以在添加 ReceivedCompleted 事件处理程序后使用BeginReceive 方法启动队列请求,然后在完成的事件处理程序中处理消息并重新启动请求。

    问题是如果你发出一个 Receive 请求,它会阻塞后台工作线程,直到队列中收到一条消息,而 CancelAsync 只会请求停止后台工作线程,它不会取消 Receive 请求.

    例如(更新):

    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));
            }
        }
    
    }
    

    【讨论】:

    • 是的,这就是我所做的,已经调用了 CancelAsync() 但无济于事。还有什么想法吗?我知道我可以使用时间跨度,但我不想使用,因为由于时间跨度,我可能会延迟阅读一些消息。所以我需要在消息进入队列时阅读它。
    • @Shax:我建议您重写代码以使用上面的方法 2,因为您当前的实现将挂起后台工作线程,直到队列中收到新消息。
    • 我也尝试了第二种方法,但反应相同,你能分享一些代码来实现它,非常感谢你在这方面的支持。
    • @Shax:我已经用一个可以得到你想要的形式的版本更新了答案。在表单关闭事件中,我们关闭消息队列并设置一个标志。在 receivecompleted 事件中,我们仅在 formclosure 事件尚未触发时才处理请求。这应该可以满足您的需求。
    • 我会测试代码并在这里更新,谢谢帮助
    【解决方案2】:

    当您关闭表单时,您会终止工作人员吗?如果没有,如果在某处有对表单或工作人员的引用(事件处理程序?),那么它将不会获得 GCd 并保留。打开第二个实例后,您可能有两个后台工作人员正在运行....

    【讨论】:

    • 是的,当我关闭表单时,我试图说 backgroundworker.cancelasync(),但这并没有帮助。你是对的,参考是一些活的,不知道我该如何阻止它......仍在尝试
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-13
    • 1970-01-01
    • 2013-02-28
    • 2013-06-03
    • 1970-01-01
    相关资源
    最近更新 更多