简体   繁体   English

C#BackgroundWorker线程问题

[英]C# BackgroundWorker Thread Problem

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace ClassLibrary
{
    public class MyClass
    {
        public static string LongOperation()
        {
            Thread.Sleep(new TimeSpan(0,0,30));

            return "HelloWorld";
        }
    }
}

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using ClassLibrary;

namespace BackgroungWorker__HelloWorld
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            if (backgroundWorker1.CancellationPending)
            {
                e.Cancel = true;
                return;
            }

            MyClass.LongOperation();

            e.Result = "[Result]";
        }

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

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                if (e.Cancelled)
                {
                    MessageBox.Show("The task has been cancelled");
                }
                else if (e.Error != null)
                {
                    MessageBox.Show("Error. Details: " + (e.Error as Exception).ToString());
                }
                else
                {
                    MessageBox.Show("The task has been completed. Results: " + e.Result!=null?e.Result.ToString():" null");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

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

        private void btnClose_Click(object sender, EventArgs e)
        {
            if (backgroundWorker1.IsBusy)
            {
                backgroundWorker1.CancelAsync();
            }
            else
            {
                this.Close();
            }
        }
    }
}

I found that, after executing the following code : 我在执行以下代码后发现:

private void btnClose_Click(object sender, EventArgs e)
        {
            if (backgroundWorker1.IsBusy)
            {
                backgroundWorker1.CancelAsync();
            }
            else
            {
                this.Close();//"this" means the Form object
            }
        }

the backgroundWorker1's thread is not killed immediately. backgroundWorker1的线程不会立即被杀死。 It takes some time. 需要一些时间。

This is been a problem in constructing my application logic. 这在构造我的应用程序逻辑时是一个问题。

Can anyone help me in this regard? 有人可以在这方面帮助我吗?

The solution is to change your BackgroundThread 's DoWork() event handler to be more responsive: it needs to break its work into smaller chunks and poll the worker's CancellationPending frequently enough to satisfy your application's needs. 解决方案是将BackgroundThreadDoWork()事件处理程序更改为更具响应性:它需要将其工作分解为较小的块,并经常轮询工作者的CancellationPending以满足应用程序的需求。


Edit : given the code you've added, you won't be able to do what you'd like with BackgroudWorker . 编辑 :给定添加的代码,您将无法使用BackgroudWorker

If you cannot modify MyClass.LongOperation (and it doesn't provide any hooks to let you interrupt it) but you want to let the user cancel before that operation finishes, you could implement this by creating your own Thread (as a background thread, which won't keep your application open if you abandon it). 如果您无法修改MyClass.LongOperation (它不提供任何钩子来让您中断它),但是您想让用户在该操作完成之前取消操作,则可以通过创建自己的Thread (作为后台线程,如果您放弃应用程序,则无法保持打开状态)。 Theoretically, you could also do it using ThreadPool.QueueUserWorkItem , except that it's a bad idea to use the ThreadPool for long-running processes (see The Managed Thread Pool for details). 从理论上讲,您也可以使用ThreadPool.QueueUserWorkItem进行此操作,除了将ThreadPool用于长时间运行的进程是个坏主意(有关详细信息,请参阅托管线程池 )。

Finally, you could consider moving the long-running operation out of band - write a message to a queue, call a service, or use some other technique to hand it off to another process. 最后,您可以考虑将长时间运行的操作移出带外-将消息写入队列,调用服务或使用其他技术将其移交给另一个进程。

This is dependent on how frequently your DoWork() method checks the CancellationPending-property. 这取决于您的DoWork()方法检查CancellationPending-property的频率。

It is a request of cancellation, you are not killing the thread. 这是取消请求,您没有杀死线程。 Refer to the msdn page on CancelAsync 请参阅有关CancelAsync的msdn页面

There is no real way to forcefully terminate the BackgroundWorker, use a Thread instead. 没有真正的方法来强制终止BackgroundWorker,请改用Thread。

It's up to the workerthreads code to check the CancellationPending property. 由工作线程代码检查CancellationPending属性。 The code that is executed in between these checks will always be executed, causing a delay. 在这些检查之间执行的代码将始终被执行,从而导致延迟。

In your remark you git a nice isssue. 在您的发言中,您给git一个好问题。

One way to solve this is building a specific subclass for multi threading, to leave the unavoidable nasty bits out of the logic. 解决此问题的一种方法是为多线程构建特定的子类,从而将不可避免的令人讨厌的位排除在逻辑之外。

The main class should provide a template method for LongOperation that calls to other methods, the threading subclass can then override the methods called in longoperation, and before letting the mainclass methods do the actual work perform the check of the CancellationPending property. 主类应该为LongOperation提供一个模板方法,该模板方法可以调用其他方法,线程子类可以覆盖longoperation中调用的方法,并且在让主类方法执行实际工作之前,对CancellationPending属性进行检查。

This way you can stop more arbitrary than at the end of longoperation. 这样,您可以比长期操作结束时停止更多的任意操作。

Multithreading in a nonfunctional way will always affect your code, hold on for when you will be needing locks ;-) 以非功能性方式进行多线程处理总是会影响您的代码,请在需要锁定时等待;-)

Can you describe what the issue is? 您能说明问题是什么吗? Surely it is better to let the background worker thread gracefully finish (as it does by design). 当然,最好让后台工作线程正常完成(这是设计使然)。

You are aware that you can periodically check for a cancellation by doing backgroundWorker1. 您知道可以通过执行backgroundWorker1来定期检查取消。 CancellationPending ? 取消待定

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM