【问题标题】:Pausing a new BackGroundWorker until previous completes暂停一个新的 BackGroundWorker 直到前一个完成
【发布时间】:2013-12-12 10:58:31
【问题描述】:

我正在努力解决线程问题。 问题是当我通过 foreach 循环进行迭代时。

设置this.Document 时,应用程序执行登录,该登录由事件触发,需要几秒钟才能完成。在worker_RunWorkerCompleted 方法中,我需要执行一些依赖于当前登录信息的操作。

问题是,在我可以对第一个文件执行此操作之前,this.Document 已经更改,使应用程序执行另一个登录。这样我就永远无法真正执行我的操作。

我的问题是:如何暂停下一个线程,直到上一个线程完成。 我的问题还有其他解决方案吗?

我尝试使用AutoResetEvent,但没有运气。我在 RunWorkerAsync 调用之后设置了waitOne(),在 RunWorkerCompleted 中设置了.Set()。代码永远不会到达RunWorkerCompleted...

代码如下:

    public void Start(object obj)
    {
       try
       {
          foreach (KeyValuePair<string, Stream> pair in this.CollectionOfFiles)
          {
              Worker = new BackgroundWorker();
              Worker.DoWork += new DoWorkEventHandler(worker_DoWork);
              Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);

          using (Stream stream = pair.Value)
              {
                primaryDocument = new Document(stream);

                DataHolderClass dataHolder = new DataHolderClass();
                dataHolder.FileName = pair.Key;
                dataHolder.Doc = secondaryDocument;

               //background thread call
                Worker.RunWorkerAsync(dataHolder);
              }
            }
          }

       catch (Exception ex)
       {
          // exception logic
}
       finally
       {
          // complete logic
       }
    }


    private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
       DataHolderClass dataHolder = ((DataHolderClass)e.Argument);
       // setting this attribute triggers execution of login event
       this.Document = dataHolder.Doc;
       e.Result = (dataHolder);
    }


    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
       // here I need to perform some actions that are depending on the current login
       DataHolderClass dataHolder = ((DataHolderClass)e.Result);
       this.eventAggregator.GetEvent<ActionEvent>().Publish(new Message(EMessageType.Info) { Title = dataHolder.FileName });
    }

【问题讨论】:

  • Worker.RunWorkerAsync(dataHolder); 时很忙又被击中了……
  • 我做对了吗?设置文档触发器以某种方式启动?
  • not... 设置 Document 触发登录操作(此处未显示)。当我在 worker_RunWorkerCompleted 中时,我需要执行一些检查登录的操作。登录需要几秒钟才能完成,它是一个基于事件的调用。我的情况是,当我到达 worker_RunWorkerCompleted 时,登录已经改变,因为集合中的另一个项目设置了 this.Document...
  • 天哪,你的比赛条件太糟糕了。如果您一次记录多次(有意?),为什么要使用单个 (this.Document) 属性?这种设计看起来很奇怪。
  • 如果RunWorkerCompleted 需要当前登录,则在同一个线程中进行。如果它们在不同的线程中,那么当然可以先完成一个,这就是线程的设计目的......

标签: c# .net wpf multithreading


【解决方案1】:

9,

尝试以下方法:

System.Threading.ManualResetEvent _busy = new System.Threading.ManualResetEvent(false);

void ResumeWorker() 
{
     // Start the worker if it isn't running
     if (!backgroundWorker1.IsBusy) backgroundWorker1.RunWorkerAsync(dataHolder);  
     // Unblock the worker 
     _busy.Set();
}

void PauseWorker() 
{
    // Block the worker
    _busy.Reset();
}

void CancelWorker() 
{
    if (backgroundWorker1.IsBusy) {
        // Set CancellationPending property to true
        backgroundWorker1.CancelAsync();
        // Unblock worker so it can see that
        _busy.Set();
    }
}

然后在您的代码中运行该方法。

让我知道它是否有效:)

【讨论】:

    【解决方案2】:
    class SimpleWaitPulse
    {
      static readonly object _locker = new object();
      static bool _go;
    
      static void Main()
      {                                // The new thread will block
        new Thread (Work).Start();     // because _go==false.
    
        Console.ReadLine();            // Wait for user to hit Enter
    
        lock (_locker)                 // Let's now wake up the thread by
        {                              // setting _go=true and pulsing.
          _go = true;
          Monitor.Pulse (_locker);
        }
      }
    
      static void Work()
      {
        lock (_locker)
          while (!_go)
            Monitor.Wait (_locker);    // Lock is released while we’re waiting
    
        Console.WriteLine ("Woken!!!");
      }
    }
    

    你能用脉冲吗? 取自:Threading in C# from albahari.com

    【讨论】:

      【解决方案3】:

      好吧,这个设计很糟糕......但是如果需要坚持下去,你可以在前一个工人中设置等待句柄,然后在下一个工人中等待它.这是最小的修复,仍然是相当可恶的:

      public void Start(object obj)
      {
          try
          {
              BackgroundWorker previousWorker = null;
              DataHolderClass previousWorkerParams = null;
      
              foreach (KeyValuePair<string, Stream> pair in this.CollectionOfFiles)
              {
                  // signal event on previous worker RunWorkerCompleted event
                  AutoResetEvent waitUntilCompleted = null;
                  if (previousWorker != null)
                  {
                      waitUntilCompleted = new AutoResetEvent(false);
                      previousWorker.RunWorkerCompleted += (o, e) => waitUntilCompleted.Set();
      
                      // start the previous worker
                      previousWorker.RunWorkerAsync(previousWorkerParams);
                  }
      
                  Worker = new BackgroundWorker();
      
                  Worker.DoWork += (o, e) =>
                  {
                      // wait for the handle, if there is anything to wait for
                      if (waitUntilCompleted != null)
                      {
                          waitUntilCompleted.WaitOne();
                          waitUntilCompleted.Dispose();
                      }
                      worker_DoWork(o, e);
                  };
      
                  using (Stream stream = pair.Value)
                  {
                      primaryDocument = new Document(stream);
      
                      DataHolderClass dataHolder = new DataHolderClass();
                      dataHolder.FileName = pair.Key;
                      dataHolder.Doc = secondaryDocument;
      
                      // defer running this worker; we don't want it to finish
                      // before adding additional completed handler
                      previousWorkerParams = dataHolder;
                  }
      
                  previousWorker = Worker;
              }
      
              if (previousWorker != null)
              {
                  previousWorker.RunWorkerAsync(previousWorkerParams);
              }
          }
      
          catch (Exception ex)
          {
              // exception logic
          }
          finally
          {
              // complete logic
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2018-03-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-23
        • 1970-01-01
        • 2012-04-19
        • 1970-01-01
        相关资源
        最近更新 更多