C# 如何使父线程等待子线程完成-C

C# 如何使父线程等待子线程完成-C,c#,multithreading,C#,Multithreading,我正在运行一个后台线程从数据库中获取数据,这样当前的threadUI就不会冻结。我正在使用第三方物流来实现这一点 List<string> _myList1, _myList2; private void LoadCollections(){ Task db_task = new Task(() => CallDB()); var continuations = db_task.ContinueWith((ant) => { _my

我正在运行一个后台线程从数据库中获取数据,这样当前的threadUI就不会冻结。我正在使用第三方物流来实现这一点

List<string> _myList1, _myList2;
private void LoadCollections(){
    Task db_task = new Task(() => CallDB());
    var continuations = db_task.ContinueWith((ant) =>
    {
        _myList1 = GetDataFromMetaData1();
        _myList2 = GetDataFromMetaData2();
    });

    db_task.Start();
    LoadTemplates(); //execute only after 'db_task' completes execution
}
但这显然会在UI线程进入睡眠状态时冻结UI。那么,有人能提出一种有效的方法来处理这种情况吗


PS:LoadTemplates初始化一些ObservableCollection变量。如果在子线程db_task内调用LoadTemplates,则会引发以下错误此类型的CollectionView不支持从不同于Dispatcher线程的线程更改其SourceCollection。因此出现了线程等待的场景。

您问错了问题。在次线程上运行进程时,您永远不希望主线程等待操作完成。这只是一种浪费……您还不如在主线程上运行操作并完成它

因此,问题是:我如何让主父线程处理辅助子线程的完成

根据您收到的错误消息,您似乎正在使用WPF编写此文件。这意味着您应该问的问题的一个答案是,您可以从响应辅助线程完成的事件处理程序调用Dispatcher.Invoke

正如Terry所建议的,您可以使用async/await特性。例如,如果没有完整的代码示例,这可能很难说:

List<string> _myList1, _myList2;
private async void LoadCollections(){
    Task db_task = new Task(() => CallDB());

    var continuations = db_task.ContinueWith((ant) =>
    {
        _myList1 = GetDataFromMetaData1();
        _myList2 = GetDataFromMetaData2();
    });

    db_task.Start();

    await continuations;

    LoadTemplates(); //execute only after 'db_task' completes execution
}
换言之,继续按现在的方式安排任务,但使用async和Wait进行设置,以便仅在继续完成后调用LoadTemplates,而在初始DB任务完成之前不会执行LoadTemplates,尤其是,这样,LoadTemplates将在首先调用LoadCollections的主调度程序线程中执行

请注意,理想情况下,LoadCollections的返回类型实际上是Task。编译器更喜欢这一点,它将允许您更好地处理可能出现的异常。但是void应该很好,并且在处理事件处理程序方法时并不少见

编辑:我还想提到的是,一种涉及更彻底地更改代码但更符合异步/等待模式的替代方法是,要么简单地等待原始db_任务,然后内联执行continuations语句,即不在任务中,或者,如果这些语句本身是长时间运行的,并且应该在后台执行,以便仍然等待原始任务,然后也将继续作为自己的任务等待,而不是显式地作为DB任务的继续

例如,假设延续操作是简短的,并且可以在主线程上运行:

List<string> _myList1, _myList2;
private async void LoadCollections(){
    await Task.Run(() => CallDB());

    _myList1 = GetDataFromMetaData1();
    _myList2 = GetDataFromMetaData2();

    LoadTemplates(); //execute only after 'db_task' completes execution
}

如果我正确理解您的问题,则必须首先运行CallDB,然后才能运行GetDataFromMetaData函数,最后才能运行LoadTemplates。我将使用ansy Wait,如下所示:

    private async void LoadCollections()
    {

        await Task.Run(() => CallDB());

        Task[] tasks = new Task[1]
        {
            _myList1 = GetDataFromMetaData1(),
            _myList2 = GetDataFromMetaData2()
        };

        await Task.WhenAll(tasks); 

        LoadTemplates(); //execute only after 'db_task' completes execution

    }

您不能使用async&Wait吗?实际上,函数LoadCollections是一个messenger事件。换句话说,当用户单击UI上的按钮时,ViewModel注册以调用LoadCollections。因此,在这种情况下,我对如何使用async/Wait有点迷茫;您不能使用wait Task.Run吗?我正试图使用Dispatcher.Invoke解决问题,正如您所提到的,Dispatcher.CurrentDispatcher.InvokeLoadTemplates,DispatcherPriority.ContextIdle;。但这似乎不起作用。你知道如何使Dispatcher.Invoke响应辅助线程的完成吗?首先,define似乎不起作用。这可能是很多不同的事情。其次,为什么使用ContextIdle作为优先级?我的意思是,这应该行得通,但从正常开始,然后从正常开始怎么样。第三,虽然使用Dispatcher应该可以工作,但async/await更简单,生成的代码更清晰。你试过那样做吗?解决方案会运行。谢谢这并不重要,但我得到了一条警告消息:因为这个调用没有等待,所以在调用完成之前,当前方法的执行将继续。考虑将“等待”操作符应用到调用的结果。你知道这意味着什么吗@用户1603970:很高兴听到它正在工作。就警告而言,它的意思是:通常在异步方法中,在执行返回任务或任务的语句时,会使用wait,但您有一个不使用wait的语句。因为您不使用await,而不是像按常规编写方法那样在该点返回,它将继续执行,当然,直到到达await表达式为止。
    private async void LoadCollections()
    {

        await Task.Run(() => CallDB());

        Task[] tasks = new Task[1]
        {
            _myList1 = GetDataFromMetaData1(),
            _myList2 = GetDataFromMetaData2()
        };

        await Task.WhenAll(tasks); 

        LoadTemplates(); //execute only after 'db_task' completes execution

    }