暂停新的BackgroundWorker直到previous完成BackgroundWorker、previous

2023-09-04 10:59:45 作者:逗

我挣扎与线程。 问题是,当我遍历低谷foreach循环。

当设定 this.Document ,应用程序执行登录,即触发一个事件,并采取几秒钟即可完成。在 worker_RunWorkerCompleted 方法,我需要执行依赖于当前的登录信息的一些行动。

现在的问题是,在我能第一个文件执行此操作时, this.Document 已经改变提出申请执行另一个登录。这样我可以从来没有真正执行我的行动。

我的问题是:我怎样才能暂停下一个线程,直到previous线程完成。 是否有任何其他解决我的问题?

我试着用的AutoResetEvent ,但我没有运气。我设置 WaitOne的()只是在RunWorkerCompleted中的RunWorkerAsync通话和。设置()之后。在code永远不会到达 RunWorkerCompleted ...

下面是code:

 公共无效启动(obj对象)
    {
       尝试
       {
          的foreach(KeyValuePair<字符串,流>对在this.CollectionOfFiles)
          {
              工人=新的BackgroundWorker();
              Worker.DoWork + =新DoWorkEventHandler(worker_DoWork);
              Worker.RunWorkerCompleted + =新RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);

          使用(流流= pair.Value)
              {
                primaryDocument =新的文件(流);

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

               //后台线程调用
                Worker.RunWorkerAsync(dataHolder);
              }
            }
          }

       赶上(例外前)
       {
          //异常逻辑
}
       最后
       {
          //完整的逻辑
       }
    }


    私人无效worker_DoWork(对象发件人,DoWorkEventArgs E)
    {
       DataHolderClass dataHolder =((DataHolderClass)e.Argument);
       //设置该属性触发执行登录事件
       this.Document = dataHolder.Doc;
       e.Result =(dataHolder);
    }


    私人无效worker_RunWorkerCompleted(对象发件人,RunWorkerCompletedEventArgs E)
    {
       //这里我需要执行的根据当前登录的一些动作
       DataHolderClass dataHolder =((DataHolderClass)e.Result);
       this.eventAggregator.GetEvent< ActionEvent的>()发布(新消息(EMessageType.Info){标题= dataHolder.FileName})。
    }
 
避免春节期间被亚马逊送小红旗,这些红线千万不能碰

解决方案

那么,设计是可怕的......不过的如果的你的需要的坚持下去,你可以设置等候在previous工人把手,并等待它的下一个。这是基本修复,还是相当可憎的:

 公共无效启动(obj对象)
{
    尝试
    {
        BackgroundWorker的previousWorker = NULL;
        DataHolderClass previousWorkerParams = NULL;

        的foreach(KeyValuePair<字符串,流>对在this.CollectionOfFiles)
        {
            //在previous工人RunWorkerCompleted事件信号事件
            的AutoResetEvent waitUntilCompleted = NULL;
            如果(previousWorker!= NULL)
            {
                waitUntilCompleted =新的AutoResetEvent(假);
                previousWorker.RunWorkerCompleted + =(O,E)=> waitUntilCompleted.Set();

                //开始previous工人
                previousWorker.RunWorkerAsync(previousWorkerParams);
            }

            工人=新的BackgroundWorker();

            Worker.DoWork + =(O,E)=>
            {
                //等待手柄,如果有任何等待
                如果(waitUntilCompleted!= NULL)
                {
                    waitUntilCompleted.WaitOne();
                    waitUntilCompleted.Dispose();
                }
                worker_DoWork(O,E);
            };

            使用(流流= pair.Value)
            {
                primaryDocument =新的文件(流);

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

                //推迟执行该工作人员;我们不希望它完成
                前//添加额外的完成处理程序
                previousWorkerParams = dataHolder;
            }

            previousWorker =工人;
        }

        如果(previousWorker!= NULL)
        {
            previousWorker.RunWorkerAsync(previousWorkerParams);
        }
    }

    赶上(例外前)
    {
        //异常逻辑
    }
    最后
    {
        //完整的逻辑
    }
}
 

I am struggling with threading. The problem is when I am iterating trough foreach loop.

When setting this.Document, the application performs login, that is triggered with an event and takes few seconds to complete. In the worker_RunWorkerCompleted method I need to perform some actions that depend on current login information.

The problem is that before I can perform this action for the first file, the this.Document already changes making the application perform another login. This way I can never actually perform my actions.

My question is: How can I pause the next thread until previous thread has completed. Is there any other solution to my problem?

I tried with AutoResetEvent but I got no luck. I set waitOne() just after the RunWorkerAsync call and .Set() in the RunWorkerCompleted. The code never gets to RunWorkerCompleted...

Here is the code:

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

解决方案

Well, the design is terrible... but if you need to stick to it, you can set wait handles in a previous worker and wait for it in next. This is the minimal fix, still quite an abomination:

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