C#BackgroundWorker线程问题

发布于 2024-08-06 12:55:20 字数 2785 浏览 3 评论 0原文

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

我发现,执行以下代码后:

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

backgroundWorker1的线程没有立即被杀死。这需要一些时间。

这是构建我的应用程序逻辑时遇到的问题。

有人可以在这方面帮助我吗?

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. It takes some time.

This is been a problem in constructing my application logic.

Can anyone help me in this regard?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

薄情伤 2024-08-13 12:55:20

解决方案是更改 BackgroundThreadDoWork() 事件处理程序以提高响应速度:它需要将其工作分解为更小的块并轮询工作线程的 CancellationPending 足够频繁以满足您的应用程序的需求。


编辑:根据您添加的代码,您将无法使用 BackgroudWorker 执行您想要的操作。

如果您无法修改 MyClass.LongOperation (并且它不提供任何钩子来让您中断它),但您想让用户在该操作完成之前取消,您可以通过创建自己的来实现Thread(作为后台线程,如果您放弃它,它不会使您的应用程序保持打开状态)。理论上,您也可以使用 ThreadPool.QueueUserWorkItem 来完成此操作,但对于长时间运行的进程使用 ThreadPool 是一个坏主意(请参阅 托管线程池了解详细信息)。

最后,您可以考虑将长时间运行的操作移出带外 - 将消息写入队列、调用服务或使用某种其他技术将其移交给另一个进程。

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.


Edit: given the code you've added, you won't be able to do what you'd like with 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). 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).

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.

祁梦 2024-08-13 12:55:20

这取决于您的 DoWork() 方法检查 CancellationPending 属性的频率。

这是取消请求,您并没有杀死线程。 的 msdn 页面

请参阅 CancelAsync上 没有真正的方法来强制终止BackgroundWorker,请使用Thread。

This is dependent on how frequently your DoWork() method checks the CancellationPending-property.

It is a request of cancellation, you are not killing the thread. Refer to the msdn page on CancelAsync

There is no real way to forcefully terminate the BackgroundWorker, use a Thread instead.

清晰传感 2024-08-13 12:55:20

由工作线程代码来检查 CancellationPending 属性。
在这些检查之间执行的代码将始终被执行,从而导致延迟。

在你的评论中,你提出了一个很好的问题。

解决这个问题的一种方法是为多线程构建一个特定的子类,以将不可避免的讨厌的部分排除在逻辑之外。

主类应该为 LongOperation 提供一个调用其他方法的模板方法,然后线程子类可以重写 longOperation 中调用的方法,并在让主类方法执行实际工作之前执行 CancellationPending 属性的检查。

这样你可以比长操作结束时更随意地停止。

以非功能性方式进行的多线程总是会影响您的代码,当您需要锁时请坚持下去;-)

It's up to the workerthreads code to check the CancellationPending property.
The code that is executed in between these checks will always be executed, causing a delay.

In your remark you git a nice isssue.

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.

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

迟月 2024-08-13 12:55:20

您能描述一下问题是什么吗?当然,最好让后台工作线程优雅地完成(正如设计所言)。

您知道,您可以通过执行backgroundWorker1定期检查取消。取消待处理

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.CancellationPending?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文