我正在进行需要调用其他异步任务的异步操作。我试图通过使用BackgroundWorkers来保持简单,结果是一个BackgroundWorker的DoWork()回调调用一个创建第二个BackgroundWorker的方法,就像这样(减去错误检查和所有爵士乐的简洁):
class Class1
{
private BackgroundWorker _worker = null;
public void DoSomethingAsync()
{
_worker = new BackgroundWorker();
_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_worker_RunWorkerCompleted);
_worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
_worker.RunWorkerAsync();
}
void _worker_DoWork(object sender, DoWorkEventArgs e)
{
Class2 foo = new Class2();
foo.DoSomethingElseAsync();
while(foo.IsBusy) Thread.Sleep(0); // try to wait for foo to finish.
}
void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// do stuff
}
}
class Class2
{
private BackgroundWorker _worker = null;
Thread _originalThread = null;
public AsyncCompletedEventHandler DoSomethingCompleted;
public bool IsBusy { get { return _worker != null && _worker.IsBusy; } }
public void DoSomethingElseAsync()
{
_originalThread = Thread.CurrentThread;
_worker = new BackgroundWorker();
_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_worker_RunWorkerCompleted);
_worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
_worker.RunWorkerAsync();
}
void _worker_DoWork(object sender, DoWorkEventArgs e)
{
// do stuff
}
void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Debug.Assert(Thread.CurrentThread == _originalThread); // fails
// Assuming the above Assert() were excluded, the following event would be raised on the wrong thread.
if (DoSomethingCompleted != null) DoSomethingCompleted(this, new AsyncCompletedEventArgs(e.Error, e.Cancelled, null));
}
}
所以问题是,我期望Class2._Worker_RunWorkerCompleted()在调用Class2.DoSomethingElseAsync()的同一个线程上执行。这种情况从未发生过 - 相反,回调运行在一个全新的线程上。
这是我的怀疑:Class1的_worker_DoWork()永远不会返回,这意味着线程永远不会回到事件监听器,即使存在一个(我怀疑没有)。另一方面,如果_worker_DoWork()确实返回,Class1的BackgroundWorker会自动提前完成 - 它需要等待Class2完成工作才能完成其工作。
这导致两个问题:
答案 0 :(得分:5)
如果在UI线程上创建BackgroundWorker
,DoWork
将在线程池线程上运行,RunWorkerCompleted
将在UI线程上运行。
如果在后台线程上创建BackgroundWorker
(即不是UI线程),DoWork
仍将在线程池线程上运行,RunWorkerCompleted
也将在线程池线程上运行
在您的情况下,由于您无法封送对任意(线程池)线程的调用,您将无法保证所需的行为,尽管您可能需要查看{{1} }。
答案 1 :(得分:0)
您应该使用ManualResetEvent在线程之间进行通信:
http://msdn.microsoft.com/en-us/library/system.threading.manualresetevent%28VS.71%29.aspx
答案 2 :(得分:0)
首先,我看不到任何实际开始运行工作人员的地方。您可以更改DoSomethingAsync方法(也可以在Class2中添加对DoSomethingElseAsync方法的调用)
public void DoSomethingAsync()
{
_worker = new BackgroundWorker();
_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_worker_RunWorkerCompleted);
_worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
_worker.RunWorkerAsync(); // add this line to start it
}
其次,工作处理程序(_worker_DoWork方法)不能保证与调用DoSomethingAsync在同一个线程上 - 这是后台工作者的全部要点。 ie /在另一个线程上工作。这同样适用于worker完成处理程序(_worker_RunWorkerCompleted方法)。
最后,附加两个不同的后台工作者似乎没有意义,除非顶级一级(Class1)总是要求Class2工作。你最好让一个经理来处理每个后台员工。