我正在编写一个重复运行一系列数字IO操作的Windows应用程序。
当用户单击“开始”按钮时,此操作序列开始,并由后台工作人员在backgroundWorker1_DoWork()中完成。
然而,有时候我会得到“这个背景工作者当前很忙.......”的错误信息。
我正在考虑在代码中实现以下内容,在启动另一个操作序列之前使用while循环“杀死”后台工作程序:
if (backgroundWorker1.IsBusy == true)
{
backgroundWorker1.CancelAsync();
while (backgroundWorker1.IsBusy == true)
{
backgroundWorker1.CancelAsync();
}
backgroundWorker1.Dispose();
}
backgroundWorker1.RunWorkerAsync();
我认为我主要担心的是,backgroundWorker1最终会被“杀死”吗?如果愿意,完成它需要很长时间吗?
这种编码会让我陷入无限循环吗?
答案 0 :(得分:74)
你可以使用这样的东西(有关中止托管线程和ThreadAbortException的更多信息,请参阅Chris Sells的“Plumbing the Depths of the ThreadAbortException Using Rotor”):
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();
}
答案 1 :(得分:18)
我认为线程应该尽可能地负责他们的自己的资源,包括他们自己的生命。
从范围之外杀死线程通常是一个坏主意。设计用于将消息传递给线程以关闭本身的应用程序往往具有与多线程行为相关的问题少得多。
一个线程应该监视所述消息,该消息可以像另一个线程设置的布尔一样简单,并由该监视线程及时读取,并且只要它干净地关闭干净地可以。
这意味着它应该查找消息:
使用该消息将其关闭的线程应该等待(但当然不要暂停GUI)。
请注意,具有特定功能的线程环境还有其他可能性,例如线程可以随意标记自己可取消的情况,以允许外部查杀更安全。
但是,建立你的应用程序以留下自己命运的主线通常仍然更容易。
答案 2 :(得分:0)
我遇到了同样的问题,我不确定这是否会有所帮助,但我猜你的后台工作者有一个循环或者它会退出。 你需要做的就是把你的循环放在里面。
放入你的后台工作人员:
while (backgroundworker1.CancellationPending == false)
{
//Put your code in here
}
要杀死此背景工作者,您可以按下按钮:
BackgroundWorker1.CancelAsync()
我希望这会有所帮助。
答案 3 :(得分: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基本上运行,直到子线程完成或我们发信号通知它终止进程。然后,后台工作线程可以返回读池。通常我会将它包装在一个帮助器类中,并传递我希望后台线程作为参数传入的委托方法并在子线程中运行它。
请有人让我知道,如果我把头撞到墙上但似乎工作正常..但那就是线程的问题不是它......你在不同的时间运行它会得到不同的结果。
答案 4 :(得分: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) ...
// .........
// .........
}
答案 5 :(得分:-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来杀死线程并且没有中止问题:)