暂停新的BackGroundWorker直到上一次完成

时间:2013-12-12 10:58:32

标签: c# .net wpf multithreading

我正在努力进行线程化。 问题是当我通过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 });
    }

3 个答案:

答案 0 :(得分:0)

NO9,

尝试以下方法:

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();
    }
}

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

让我知道它是否有效:)

答案 1 :(得分:0)

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

答案 2 :(得分:0)

嗯,设计很糟糕......但如果你需要坚持下去,你可以在之前的工作人员中设置等待句柄并在下一个等待它。这是最小的修复,仍然是令人厌恶的:

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
    }
}