使用标志退出 BackgroundWorker

Quitting BackgroundWorker using flag

假设我有这样的代码:

 private bool flag = false;
 public SomeClass()
 {
     public void setup()
    {
        worker = new BackgroundWorker();
        worker.DoWork += worker_DoWork;

        if(!worker.IsBusy)
            worker.RunWorkerAsync();
    }

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        if(flag == true)
          return;
        //whatever You want the background thread to do...
        SomeClass.SomeStaticMethodWhichHasLoopInside();
    }
}

当用户在我的应用程序中单击“退出”按钮时,我可以在其中设置 flag=true - 这是停止由 BackgroundWorker 启动的线程的正确方法吗? 我只想在应用程序想要退出时这样做——这样我就可以停止线程。还是自动杀掉?

没有。不要那样做。它不会按预期工作。您的 flag 字段甚至没有声明为 volatile;该字段的真实值可能尚未刷新到内存中。其他线程仍然会看到 flag 为假,因为它缓存了自己的值副本,而您的 BackgroundWorker 可能永远不会结束。

相反,只需在 DoWork 事件处理程序中调用 BackgroundWorker.CancelAsync and check for BackgroundWorker.CancellationPending 布尔值。

private void OnExit(..)
{
    worker.CancelAsync();
}

所以你的 DoWork 方法将变成

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    while(!worker.CancellationPending)
    {
        //whatever You want the background thread to do...
    }
}

如果没有循环,需要时不时检查CancellationPending属性

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    if(worker.CancellationPending)
        return;
    //Do something..
    if(worker.CancellationPending)
        return;
    //Do some other thing..
    if(worker.CancellationPending)
        return;
    //Do something else..
}

I want to do this only when application wants to quit - so that I stop the thread. Or it will be automatically killed?

由于该线程是后台线程,它会被 CLR 自动终止。但是,不要依赖这个事实,因为我们不知道在 CLR 终止线程时您的线程将执行什么。例如,它可能一直在写入一个文件,在这种情况下,您会留下损坏的文件。

后果可能更糟,因此始终建议您自己优雅地停止线程。

Question asked in comments: How can I cancel when the loop is in some other method?

看来您使用的是.Net4.5。您可以利用 CancellationTokenSourceCancellationToken。您也可以考虑使用 TPL 和 async-await 功能,这将使您的生活更轻松。

private CancellationTokenSource tokenSource = new CancellationTokenSource();

private void OnExit(..)
{
    tokenSource.Cancel();
}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    //whatever You want the background thread to do...
    SomeClass.SomeStaticMethodWhichHasLoopInside(tokenSource.Token);
}

class SomeClass
{
    public static void SomeStaticMethodWhichHasLoopInside(CancellationToken token)
    {
        while (!token.IsCancellationRequested)
        {
            //Do something
        }
    }
}