C# 暂停新的BackGroundWorker,直到上一个完成
我正在努力解决线程问题。 问题是当我通过foreach循环迭代时 设置C# 暂停新的BackGroundWorker,直到上一个完成,c#,.net,wpf,multithreading,C#,.net,Wpf,Multithreading,我正在努力解决线程问题。 问题是当我通过foreach循环迭代时 设置此.Document时,应用程序将执行登录,该操作由事件触发,需要几秒钟才能完成。在worker\u RunWorkerCompleted方法中,我需要根据当前登录信息执行一些操作 问题是,在我可以对第一个文件执行此操作之前,this.Document已经更改,使应用程序执行另一次登录。这样的话,我就永远不能真正地执行我的行为 我的问题是:如何暂停下一个线程,直到上一个线程完成。 我的问题还有别的解决办法吗 我尝试了AutoR
此.Document
时,应用程序将执行登录,该操作由事件触发,需要几秒钟才能完成。在worker\u 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 });
}
公共作废开始(对象obj)
{
尝试
{
foreach(此.CollectionOfFiles中的KeyValuePair对)
{
Worker=新的BackgroundWorker();
Worker.DoWork+=新的doworkereventhandler(Worker\u DoWork);
Worker.RunWorkerCompleted+=新的RunWorkerCompletedEventHandler(Worker\u RunWorkerCompleted);
使用(Stream=pair.Value)
{
primaryDocument=新文档(流);
DataHolderClass dataHolder=新DataHolderClass();
dataHolder.FileName=pair.Key;
dataHolder.Doc=第二个文档;
//后台线程调用
Worker.RunWorkerAsync(数据持有者);
}
}
}
捕获(例外情况除外)
{
//异常逻辑
}
最后
{
//完全逻辑
}
}
私有void worker_DoWork(对象发送方,DoWorkEventArgs e)
{
DataHolderClass dataHolder=((DataHolderClass)e.Argument);
//设置此属性将触发登录事件的执行
this.Document=dataHolder.Doc;
e、 结果=(数据持有者);
}
私有void worker\u RunWorkerCompleted(对象发送方,RunWorkerCompletedEventArgs e)
{
//在这里,我需要根据当前登录执行一些操作
DataHolderClass dataHolder=((DataHolderClass)e.Result);
this.eventAggregator.GetEvent().Publish(新消息(EMessageType.Info){Title=dataHolder.FileName});
}
第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();
}
}
然后在代码中运行该方法
让我知道它是否有效:)
你会用脉搏吗?
摘自:嗯,设计很糟糕。。。但如果您需要坚持使用它,您可以在前一个worker中设置等待句柄,并在下一个worker中等待它。这是最基本的解决方案,仍然是一个令人憎恶的问题:
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
}
}
公共作废开始(对象obj)
{
尝试
{
BackgroundWorker-previousWorker=null;
DataHolderClass previousWorkerParams=null;
foreach(此.CollectionOfFiles中的KeyValuePair对)
{
//上一个worker RunWorkerCompleted事件上的信号事件
AutoResetEvent WaitUntillCompleted=null;
if(previousWorker!=null)
{
waitUntilCompleted=新自动重置事件(假);
previousWorker.RunWorkerCompleted+=(o,e)=>WaitUntillCompleted.Set();
//启动上一个工作进程
previousWorker.RunWorkerAsync(previousWorkerParams);
}
Worker=新的BackgroundWorker();
Worker.DoWork+=(o,e)=>
{
//如果有什么需要等待的,请等待手柄
如果(WaitUntillCompleted!=null)
{
waituntlcompleted.WaitOne();
waituntlcompleted.Dispose();
}
工人工作(o、e);
};
使用(Stream=pair.Value)
{
primaryDocument=新文档(流);
DataHolderClass dataHolder=新DataHolderClass();
dataHolder.FileName=pair.Key;
dataHolder.Doc=第二个文档;
//推迟运行此worker;我们不希望它完成
//在添加其他已完成的处理程序之前
previousWorkerParams=数据持有者;
}
以前的工人=工人;
}
if(previousWorker!=null)
{
previousWorker.RunWorkerAsync(previousWorkerParams);
}
}
捕获(例外情况除外)
{
//异常逻辑
}
最后
{
//完全逻辑
}
}
它是在Worker.RunWorkerAsync(数据持有者)运行时生成的;又被击中了…我没弄错吧?设置文档触发器是否以某种方式启动?不是。。。设置文档会触发登录操作(此处未显示)。当我在worker\u Runworker Completed中时,我需要执行一些检查登录的操作。登录只需几秒钟即可完成,这是一个基于事件的调用。我的情况是,当我到达worker\u RunWorker完成时,登录名已经更改,因为集合中的另一项设置了此。文档…哦,天哪,您的竞争条件太糟糕了。如果您一次记录多次日志(有意吗?),为什么要使用单个(this.Document)属性?这个设计看起来很奇怪。如果RunWorkerCompleted
需要当前登录,那么在同一个线程中执行它们。如果它们在不同的线程中,那么当然一个线程可以在另一个线程之前完成,这就是线程的设计目的。。。
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
}
}