【问题标题】:Quitting BackgroundWorker using flag使用标志退出 BackgroundWorker
【发布时间】:2015-05-14 06:56:38
【问题描述】:

想象一下我有这样的代码:

 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 启动的线程的正确方法吗? 我只想在应用程序想要退出时才这样做 - 这样我就停止了线程。还是会被自动杀死?

【问题讨论】:

  • 最佳实践写在Sriram Sakthivel's answer 但是我必须提到,如果您将flag 标记为volatile,您的解决方案可能会起作用。如果没有 volatile 关键字 - 它可以防止变量被缓存 - 优化器可能会将线程的 flag 存储在 L2 或寄存器中,而主线程的 flag 存储在 RAM 中,所以你没有 @ 987654330@ 你的帖子可能永远不会得到通知。

标签: c# multithreading backgroundworker


【解决方案1】:

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

相反,只需调用 BackgroundWorker.CancelAsync 并检查 DoWork 事件处理程序中的 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..
}

我只想在应用程序想要退出时才这样做 - 这样我就停止了 线程。还是会被自动杀死?

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

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

在 cmets 中提出的问题:当循环处于某些状态时如何取消 其他方法?

看来您使用的是 .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
        }
    }
}

【讨论】:

  • worker_Dowork 方法中调用的方法中有一个循环 - 但该方法来自另一个类 - 我如何从该方法中引用 worker?将worker设为静态?
  • 您的意思是:postimg.org/image/efldufscd?或者这个 postimg.org/image/gefw4bu9f 请提供解决方案的完整代码 - 我对 C# 有点陌生
  • 我已经更新了使用SomeStaticMethodWhichHasLoopInside 时线程看起来如何的问题 - 请说明我将如何通过该方法检查该属性
  • 为什么我不能将worker 声明为静态并从SomeStaticMethodWhichHasLoopInside 检查SomeClass.Static_worker.CancellationPending——看起来更容易??
  • @user300455 这不是一个好习惯。我不鼓励使用静态。如果你愿意,你可以这样做。但我推荐正确的方法,就在我的答案中。
猜你喜欢
  • 2021-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-15
  • 1970-01-01
  • 1970-01-01
  • 2020-01-19
相关资源
最近更新 更多