C# 如何完全“杀死”后台工作者?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/800767/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 01:42:41  来源:igfitidea点击:

How to "kill" background worker completely?

c#backgroundworker

提问by

I am writing a windows application that runs a sequence of digital IO actions repeatedly.

我正在编写一个 Windows 应用程序,它重复运行一系列数字 IO 操作。

This sequence of actions starts when the user click a "START" button, and it is done by a background worker in backgroundWorker1_DoWork().

这一系列操作在用户单击“开始”按钮时开始,由 backgroundWorker1_DoWork() 中的后台工作人员完成。

However, there are occasions when I get the "This backgroundworker is currently busy......." error message.

但是,有时我会收到“此后台工作人员当前正忙......”错误消息。

I am thinking of implementing the following in the code, by using a while loop to "kill" the background worker before starting another sequence of action:

我正在考虑在代码中实现以下内容,在开始另一个操作序列之前使用 while 循环“杀死”后台工作人员:

if (backgroundWorker1.IsBusy == true)
{

    backgroundWorker1.CancelAsync();
    while (backgroundWorker1.IsBusy == true)
    {
        backgroundWorker1.CancelAsync();
    }

    backgroundWorker1.Dispose();

}

backgroundWorker1.RunWorkerAsync();

I think my main concern is, will the backgroundWorker1 be "killed" eventually? If it will, will it take a long time to complete it?

我想我主要关心的是,backgroundWorker1 最终会被“杀死”吗?如果会,完成它需要很长时间吗?

Will this coding get me into an infinite loop?

这种编码会让我陷入无限循环吗?

回答by paxdiablo

I'm of the opinion that threads should be responsible for their ownresources as much as practicable, including their own lifetime.

我认为线程应该尽可能多地对自己资源负责,包括它们自己的生命周期。

It's usually a bad idea to kill threads from outside their scope. Applications that are engineered to pass a message to the thread to shut itselfdown tend to have far less problems related to multi-threaded behavior.

从其范围之外杀死线程通常是一个坏主意。设计为将消息传递给线程以关闭自身的应用程序往往与多线程行为相关的问题要少得多。

A thread should monitor for said message, which can be as simple as a boolean set by another thread and read by that monitoring thread, in a timely fashion and shut itself down cleanlyas soon as it can.

一个线程应该监控所述消息,该消息可以像另一个线程设置的布尔值一样简单,并由该监控线程读取,及时并尽快干净地关闭自己。

That means if it should look for the message:

这意味着它是否应该查找消息:

  • in it's main loop, if any.
  • periodically in any long-running loops.
  • 在它的主循环中,如果有的话。
  • 定期在任何长时间运行的循环中。

The thread shutting it down with the message should wait (but don't halt the GUI, of course).

用消息关闭它的线程应该等待(但不要停止 GUI,当然)。

Note that there are other possibilities for threaded environments with specific capabilities such as the case where threads can mark themselves cancellable at will, to allow external killing to be safer.

请注意,具有特定功能的线程环境还有其他可能性,例如线程可以随意将自己标记为可取消的情况,以允许外部杀死更安全。

But it's still usually easier to just architect your application to leave a thread master of its own destiny.

但是通常更容易构建应用程序,让线程主宰自己的命运。

回答by echrom

I was having the same problem, I'm not sure if this will help but I'm guessing your background worker has a loop within or it would exit. What you need to do is put your loop within.

我遇到了同样的问题,我不确定这是否有帮助,但我猜你的后台工作人员有一个循环,否则它会退出。你需要做的是把你的循环放在里面。

Put inside your background worker:

放入你的后台工作人员:

while (backgroundworker1.CancellationPending == false)
{
    //Put your code in here
}

To kill this backgroundworker, you can put in your button:

要杀死这个后台工作者,你可以输入你的按钮:

BackgroundWorker1.CancelAsync()

I hope this helps.

我希望这有帮助。

回答by Sergey Teplyakov

You can use something like this (for more information about aborting managed threads and about ThreadAbortException see "Plumbing the Depths of the ThreadAbortException Using Rotor" by Chris Sells):

您可以使用类似的方法(有关中止托管线程和 ThreadAbortException 的更多信息,请参阅Chris Sells 的“使用 Rotor 检测 ThreadAbortException 的深度”):

public class AbortableBackgroundWorker : BackgroundWorker
{

    private Thread workerThread;

    protected override void OnDoWork(DoWorkEventArgs e)
    {
        workerThread = Thread.CurrentThread;
        try
        {
            base.OnDoWork(e);
        }
        catch (ThreadAbortException)
        {
            e.Cancel = true; //We must set Cancel property to true!
            Thread.ResetAbort(); //Prevents ThreadAbortException propagation
        }
    }


    public void Abort()
    {
        if (workerThread != null)
        {
            workerThread.Abort();
            workerThread = null;
        }
    }
}

Usage:

用法:

backgroundWorker1 = new AbortableBackgroundWorker();
//...
backgroundWorker1.RunWorkerAsync();

if (backgroundWorker1.IsBusy == true)
{
    backgroundWorker1.Abort();
    backgroundWorker1.Dispose();
}

回答by Rob

I put one together that (i think) does the job. Please let me know if im waaaay off. Here is a simple exaple of how it works.

我把一个(我认为)放在一起完成了这项工作。如果我 waaaay 关闭,请告诉我。这是它如何工作的一个简单示例。

var backgroundWorker = new BackgroundWorker(){WorkerSupportsCancellation = true};

backgroundWorker.DoWork += (sender, args) =>
         {                 
                 var thisWorker = sender as BackgroundWorker;
                 var _child = new Thread(() =>
                                               {
                                                   //..Do Some Code

                                               });
                 _child .Start();
                 while (_child.IsAlive)
                 {
                     if (thisWorker.CancellationPending)
                     {
                         _child.Abort();
                         args.Cancel = true;
                     }
                     Thread.SpinWait(1);
                 }                 
         };

 backgroundWorker.RunWorkerAsync(parameter);
 //..Do Something...
backgroundWorker.CancelAsync();

Since the background worker is part of the thread pool, we dont want to abort it. But we can run a thread internally which we can allow an abort to occur on. The backgroundWorker then basically runs until either the child thread is complete or we signal to it to kill the process. The background worker thread can then go back into the read pool. Typically I will wrap this up in a helper class and pass through the delegate method that I want the background thread to run passed in as the parameter and run that in the child thread.

由于后台工作者是线程池的一部分,我们不想中止它。但是我们可以在内部运行一个线程,我们可以允许中止发生。然后 backgroundWorker 基本上会一直运行,直到子线程完成或我们向它发出信号以终止进程。然后后台工作线程可以返回到读取池中。通常,我会将其包装在一个帮助器类中,并通过我希望后台线程运行的委托方法作为参数传入并在子线程中运行该方法。

Please someone let me know if im banging my head against a wall but it seems to work fine.. But thats the problem with threads isnt it.. the varying results you can get when you run it at different times.

请有人让我知道我是否将头撞在墙上,但它似乎工作正常..但这不是线程的问题..在不同时间运行它时可以获得不同的结果。

回答by Daniel

public class abortableBackgroundworker: BackgroundWorker
{
    public bool Kill = false;

    protected override void OnDoWork(DoWorkEventArgs e)
    {


        var _child = new Thread(() =>
        {
            while (!Kill)
            {

            }
            e.Cancel = true;//..Do Some Code

        });
        _child.Start();
        base.OnDoWork(e);

    }



}

you set kill to true to kill the thread and no abort problem :)

您将 kill 设置为 true 以终止线程并且没有中止问题:)