可以使用async / await与TPL干扰BackgroundWorker吗?

时间:2013-10-04 12:26:09

标签: multithreading winforms task-parallel-library backgroundworker async-await

我有一个遗留(几年前)的WinForms项目,目前在.NET 4.0中。大多数当前数据检索使用BackgroundWorker类/模式进行异步检索,但我正在添加一些新功能并希望使用async模式(通过{{ 3}})。这种方法在开发和测试环境中运行良好,但是我们的一些用户(非平凡数量)在程序中出现了与线程相关的错误;特别是如果除了UI线程修改UI绑定数据之外的其他东西,您可能会看到。

其中一个遗留控件的示例如下:

public class LegacyControl
{
    public void LoadData(int id)
    {
        while(isLoading)
        {
            Application.DoEvents();
            Thread.Sleep(50);
        }

        isLoading = true;

        currentId = id;

        worker.RunWorkerAsync(id);
    }

    private bool isLoading;
    private int currentId;
    private object myData;

    private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        myData = RetrieveData(currentId);
    }

    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        bindingSource.DataSource = myData;
    }
}

其中一个新控件的示例如下:

public class NewControl
{
    public void LoadData(int id)
    {
        LoadDataAsync(id).ContinueWithErrorHandling(); // custom extension method to generically handle unhandled task exceptions.
    }

    private async Task LoadDataAsync(int id)
    {
        var data = await RetrieveSomeOtherDataAsync(id);

        bindingSource.DataSource = data;
    }
}

虽然我对这种可能性持怀疑态度,但我正在试着弄清楚这里发生了什么。是否有可能使用async / await以某种方式弄乱BackgroundWorker,并且导致其RunWorkerCompleted事件在后台线程而不是UI线程上运行?

我可以尝试删除TPL代码,但由于我无法在我的环境中重现错误行为,因此我没有任何测试方法。

1 个答案:

答案 0 :(得分:3)

async根本不会混淆BackgroundWorkerBackgroundWorker是它自己完全独立的主题。

您发布的代码中最可疑的部分是DoEvents。这会创建一个嵌套的消息循环,因此您必须考虑整个应用程序,并确保您拥有的任何 UI事件处理程序(和async延续)都能正常工作如果从该方法调用,则正确。