嵌套的BackgroundWorkers:在错误的线程上运行RunWorkerCompleted?

Sea*_*n U 4 c# multithreading backgroundworker

我正在进行需要调用更多异步任务的异步操作.我试图通过使用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));
    }
}
Run Code Online (Sandbox Code Playgroud)

所以问题是,我期望Class2._Worker_RunWorkerCompleted()在调用Class2.DoSomethingElseAsync()的同一个线程上执行.这种情况从未发生过 - 相反,回调运行在一个全新的线程上.

这是我的怀疑:Class1的_worker_DoWork()永远不会返回,这意味着线程永远不会回到事件监听器,即使存在一个(我怀疑没有).另一方面,如果_worker_DoWork()确实返回,Class1的BackgroundWorker会自动提前完成 - 它需要等待Class2完成工作才能完成其工作.

这导致了两个问题:

  1. 我的怀疑是否正确?
  2. 嵌套异步操作的最佳方法是什么?我可以挽救BackgroundWorker方法,还是有其他更合适的技术?

les*_*ode 5

如果BackgroundWorker在UI线程上创建了a ,DoWork则将在线程池线程上RunWorkerCompleted运行,并将在UI线程上运行.

如果BackgroundWorker在后台线程(即不是UI线程)DoWork上创建a仍将在线程池线程上RunWorkerCompleted运行,并且还将在线程池线程上运行.

在您的情况下,由于您无法编组对任意(线程池)线程的调用,您将无法保证所需的行为,尽管您可能需要查看System.Threading.SynchronizationContext.