【问题标题】:Background worker RunWorkCompleted Event后台工作者 RunWorkCompleted 事件
【发布时间】:2015-05-06 05:16:42
【问题描述】:

我有以下 wpf 程序,我想做的是 btnAnalyzer_click 方法等待 DoWork 和 RunWorkerCompleted 方法完成。所以我使用了 AutoResetEvent,但现在 bwAnalyze_click 方法(#4 行)在 DoWork 之后运行,然后是 WorkerCompleted 方法(行顺序 - #1 #2 #4 & #3)。但我希望他们按照#1 #2 #3 & #4 的顺序执行。有什么解决方案或建议吗?

public partial class MainWindow : Window
{
    private readonly BackgroundWorker bwAnalyzer = new BackgroundWorker();
    private AutoResetEvent autoReset;//to signal the end of the BackgroudnWork

    public MainWindow()
    {
        InitializeComponent();
        autoReset = new AutoResetEvent(false);
        bwAnalyzer.DoWork += new DoWorkEventHandler(DoWork);
        bwAnalyzer.RunWorkerCompleted += new RunWorkerCompletedEventHandler(WorkerCompleted);
    }

    void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        Console.WriteLine("Completed"); #3
        autoReset.Set();
    }

    void DoWork(object sender, DoWorkEventArgs e)
    {
        Console.WriteLine("load"); #2

    }

    private void btnAnalyze_Click(object sender, RoutedEventArgs e)
    {
        bwAnalyzer.RunWorkerAsync(); #1
        autoReset.WaitOne();//when commented working properly
        Console.WriteLine("click"); #4
    }
}

【问题讨论】:

    标签: c# wpf multithreading backgroundworker


    【解决方案1】:

    虽然建议使用任务的答案会起作用,但我有点困惑为什么要等到后台工作人员完成其工作后再让 UI 线程的点击事件继续。据我了解,您使用后台工作人员是因为您希望在不阻塞 UI 的情况下执行后台工作。您提出问题的方式表明您希望在工作完成之前阻止 UI。在那种情况下,为什么要使用单独的线程呢?

    另外,关于您的评论:

    autoReset.WaitOne();//when commented working properly
    

    我假设如果您不加注释,UI 会永久阻塞?当您在按钮的单击事件中调用 autoReset.WaitOne() 时,您将阻塞 UI 线程。 DoWork 将在后台线程上运行,RunWorkerCompleted 事件在 UI 线程上运行。所以 RunWorkerCompleted 永远不会执行。

    如果您评论WaitOne() 电话,我认为它根本不会“正常”工作。我对其进行了测试,由于 UI 线程和后台线程之间的竞争,它在 click->load->completed 和 load->click->completed 之间有所不同。

    【讨论】:

    • 是的,我明白你的意思,等待和使用后台工作者是没用的。我正在编辑现有的代码库,因此删除后台工作人员似乎需要做很多工作。所以我尝试在使用后台工作人员时更改点击顺序并完成....
    • 我明白了!好吧,最简单的方法是将 RunWorkerAsync 之后的所有内容移动到一个新方法中,并在 WorkerCompleted() 中调用它......然后你保证让它线性执行而不会阻塞任何东西。虽然我必须说,为了维护的缘故,我对这样的代码有点怀疑:)
    • @Rowbear:如果您正在编辑现有代码,为什么不改进设计,因为您有机会这样做? :) "Leave the campground cleaner than the way you found it."
    • @RobinMaben:我完全同意。如果是我,我会把整个后台工作人员都撕掉。
    【解决方案2】:

    使用任务,并使用 ContinueWith 方法:https://msdn.microsoft.com/en-us/library/dd270696(v=vs.110).aspx

    【讨论】:

      【解决方案3】:

      我猜以下应该给出期望的行为 -

       private void btnAnalyze_Click(object sender, RoutedEventArgs e)
       {      
      
             Task.Factory.StartNew(() => {   
      
             })
             .ContinueWith(f => {            
      
             })
             .Wait(); 
       }
      

      【讨论】:

        【解决方案4】:

        这里的大多数答案都是正确地要求您尝试使用 TPL 做您想做的事情,但是如果您有一个复杂的场景,您需要使用 ManualResetEvent/AutoResetEvent,那么这里就是您问题的解决方案。 只需将您的 btn 单击逻辑包围在任务或线程中即可。这个想法是你不想持有 UI(STA 主)线程。这会导致一些运行时优化并导致不良行为。

        Task.Factory.StartNew(() =>
                    {
                        bwAnalyzer.RunWorkerAsync(); //#1
                        autoReset.WaitOne(); //when commented working properly
                        Console.WriteLine("click"); //#4
                    });
        

        只要有上面的 sn-p 应该会给你想要的行为。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-07-29
          • 1970-01-01
          • 2011-10-30
          • 2011-03-17
          • 1970-01-01
          相关资源
          最近更新 更多