C# 对backgroundworker未按预期停止工作感到困惑
我有以下代码。这只是一个表单应用程序。负载时,它将运行地面工作人员 然后我有一个按钮,应该通过将标志设置为true来停止后台工作程序中的无限循环 我正在记录C# 对backgroundworker未按预期停止工作感到困惑,c#,winforms,backgroundworker,C#,Winforms,Backgroundworker,我有以下代码。这只是一个表单应用程序。负载时,它将运行地面工作人员 然后我有一个按钮,应该通过将标志设置为true来停止后台工作程序中的无限循环 我正在记录backgroundworker1.IsBusy的输出,它说它正忙,但根据代码中的逻辑,它不应该忙,因为我将标志设置为true,从而退出while循环并运行backgroundworker\u Completed事件 我一定是做错了什么事,但我想不出来 如果我做得不对,有没有人能帮我纠正我做错了什么,或者给我指出一个更好的方向,告诉我如何完成
backgroundworker1.IsBusy的输出,它说它正忙,但根据代码中的逻辑,它不应该忙,因为我将标志设置为true,从而退出while循环并运行backgroundworker\u Completed
事件
我一定是做错了什么事,但我想不出来
如果我做得不对,有没有人能帮我纠正我做错了什么,或者给我指出一个更好的方向,告诉我如何完成我在这里要做的事情
private volatile bool StopScanning = false;
private void myForm_Load(object sender, EventArgs e)
{
try
{
if (backgroundWorker1.IsBusy)
{
//do nothing
}
else
{
backgroundWorker1.RunWorkerAsync();
}
}
catch (Exception boo)
{
Log.log(boo.ToString());
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (StopScanning == false)
{
Application.DoEvents();
try
{
ReturnScannedItems();
System.Threading.Thread.Sleep(1000);
}
catch (Exception boo)
{
Log.log(boo.ToString());
}
}
}
private void cancelbutton_Click(object sender, EventArgs e)
{
try
{
Log.log("Setting Stop Scan flag to true");
StopScanning = true;
Log.log(CloseScanSession().ToString());
}
catch (Exception boo)
{
Log.log("Setting Stop Scan flag to true");
StopScanning = true;
Log.log(CloseScanSession().ToString());
Log.log(boo.ToString());
}
while (backgroundWorker1.IsBusy)
{
Log.log("Still busy");
}
this.Close();
}
您正在阻止UI线程,这会阻止BackgroundWorker
完成。在UI线程可以自由处理新消息之前,它无法引发RunWorkerCompleted
事件(引发事件涉及将消息发布到UI线程的消息队列,以便UI线程可以执行实际引发事件的代码)
您的代码也有缺陷,因为它从工作线程调用了Application.DoEvents()
。无论如何,您都不应该调用此方法,但从工作线程调用它尤其愚蠢,因为拥有工作线程的全部目的是避免必须调用该方法(在工作线程上调用时,它不会做任何事情,因为工作线程不应该拥有任何需要接收窗口消息的窗口对象)
与其坐在忙碌的循环中,检查IsBusy
并阻止UI线程,您只需订阅RunWorkerCompleted
事件,然后在那里做您需要做的任何事情。如果没有一个好的例子来充分说明您实际要做的事情,那么就不可能提供任何更具体的建议。您正在阻止UI线程,这会阻止BackgroundWorker
完成。在UI线程可以自由处理新消息之前,它无法引发RunWorkerCompleted
事件(引发事件涉及将消息发布到UI线程的消息队列,以便UI线程可以执行实际引发事件的代码)
您的代码也有缺陷,因为它从工作线程调用了Application.DoEvents()
。无论如何,您都不应该调用此方法,但从工作线程调用它尤其愚蠢,因为拥有工作线程的全部目的是避免必须调用该方法(在工作线程上调用时,它不会做任何事情,因为工作线程不应该拥有任何需要接收窗口消息的窗口对象)
与其坐在忙碌的循环中,检查IsBusy
并阻塞UI线程,您只需订阅RunWorkerCompleted
事件,然后在那里做您需要做的任何事情。如果没有一个好的方法来充分说明您实际要做的事情,就不可能提供任何比这更具体的建议。do不要在后台线程上调用应用程序。DoEvents
!最初我在cancelbutton\u Click方法中有它,但我正在搜索,发现有人在doWork中有它。两人都没有difference@Yarik:我将更进一步:不要调用Application.DoEvents()
,句号。修复代码中的一些设计缺陷总是一种黑客行为,最好是修复设计,这样就根本不需要它。只是一个旁注:任何“如果某个条件那么就什么都不做”都可以替换为“如果不是某个条件那么就做些什么”因此,如果(!backgroundWorker1.IsBusy){backgroundWorker1.RunWorkerAsync();}
这样你就不需要else
分支了。不要在后台线程上调用应用程序。DoEvents
!最初我在cancelbutton\u Click方法中使用了它,但我在搜索时发现有人在doWork中使用了它。两人都没有做任何更改difference@Yarik:我将更进一步:不要调用Application.DoEvents()
,句号。修复代码中的某些设计缺陷总是一种黑客行为,最好是修复设计,这样就根本不需要它。只是一个旁注:任何“如果某个条件那么就什么都不做”都可以替换为“如果不是某个条件那么就做些什么”。因此,如果(!backgroundWorker1.IsBusy){backgroundWorker1.RunWorkerAsync();}
您应该使用,这样您就不需要else
分支了。感谢您的帮助。我已经有了应用程序。DoEvents()在cancel方法中,但现在我知道它不应该被使用。我只是在cancel方法中检查isBusy,看看它什么时候不会忙,因为在理论上,至少在我看来,它在单击cancel按钮后不应该长时间忙。如果我放置应用程序。DoEvents()在cancel中,它可以工作。只是它需要一段时间来执行this.Close(),这是因为出于某种原因,它仍然很忙…它需要几秒钟才能执行Close()操作函数。如果没有一个好的函数,就没有足够的信息来知道为什么会出现延迟。这可能是因为忙循环,它有消耗CPU时间和阻止其他线程执行的趋势,如果在同一个循环中包含对Thread.Sleep(1)
的调用,它会工作得更好(但这和调用Application.DoEvents()
)一样糟糕。或者你没有共享的其他代码中有什么东西导致了它。谢谢你的帮助。我确实有这个应用程序。DoEvents()在cancel方法中,但现在我知道它不应该被使用。我只是在cancel方法中检查isBusy,看看什么时候它不会被使用