58

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

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

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

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

if (backgroundWorker1.IsBusy == true)
{

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

    backgroundWorker1.Dispose();

}

backgroundWorker1.RunWorkerAsync();

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

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

4

6 回答 6

79

您可以使用这样的东西(有关中止托管线程和 ThreadAbortException 的更多信息,请参阅Chris Sells 的“使用转子(Web 存档)探测 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;
        }
    }
}

用法:

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

if (backgroundWorker1.IsBusy == true)
{
    backgroundWorker1.Abort();
    backgroundWorker1.Dispose();
}
于 2010-01-20T20:22:44.407 回答
20

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

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

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

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

  • 在它的主循环中,如果有的话。
  • 定期在任何长时间运行的循环中。

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

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

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

于 2009-04-29T03:41:10.643 回答
1

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

放入您的后台工作人员:

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

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

BackgroundWorker1.CancelAsync()

我希望这有帮助。

于 2010-01-12T11:43:18.317 回答
0

我把一个(我认为)放在一起可以完成这项工作。请让我知道我是否离开了。这是一个简单的例子,说明它是如何工作的。

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

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

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

于 2010-04-07T03:04:40.313 回答
0

我只是使用'return'转到线程末尾:

private void myWorker_DoWork(object sender, DoWorkEventArgs e)
{
   // some variables 

   while(true)
   {
      // do something ...
      if(need_cancel) return;
      else doSomeThingElse();
   }

   // may be more code here (ignored if 'return' is executed) ...
   // .........
   // .........
}
于 2020-10-09T11:44:50.613 回答
-1
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);

    }



}

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

于 2011-09-04T05:54:55.500 回答