C# 对backgroundworker未按预期停止工作感到困惑

C# 对backgroundworker未按预期停止工作感到困惑,c#,winforms,backgroundworker,C#,Winforms,Backgroundworker,我有以下代码。这只是一个表单应用程序。负载时,它将运行地面工作人员 然后我有一个按钮,应该通过将标志设置为true来停止后台工作程序中的无限循环 我正在记录backgroundworker1.IsBusy的输出,它说它正忙,但根据代码中的逻辑,它不应该忙,因为我将标志设置为true,从而退出while循环并运行backgroundworker\u Completed事件 我一定是做错了什么事,但我想不出来 如果我做得不对,有没有人能帮我纠正我做错了什么,或者给我指出一个更好的方向,告诉我如何完成

我有以下代码。这只是一个表单应用程序。负载时,它将运行地面工作人员

然后我有一个按钮,应该通过将标志设置为true来停止后台工作程序中的无限循环

我正在记录
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,看看什么时候它不会被使用