【问题标题】:How to make the parent thread wait for the child thread to complete - C#如何让父线程等待子线程完成 - C#
【发布时间】:2014-10-19 23:21:45
【问题描述】:

我正在运行一个后台线程来从数据库中获取数据,这样当前线程(UI)就不会冻结。我正在使用 TPL 来实现这一点。

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
}

在上面的代码中

CallDB() - 从数据库中获取数据并将其存储在元数据中。在这种情况下,将其视为字符串列表。 (比如List&lt;string&gt; MetaStrings

GetDataFromMetaData1()GetDataFromMetaData2() - 获取 2 个单独的列表,它们是 MetaStrings 的子列表。

现在我希望仅在 _myList1_myList2 加载后执行函数 LoadTemplates,即当 db_task 完成执行时。目前,我正在使用这个

while(_mylist1==null && _mylist2==null)
    Thread.Sleep(50);

LoadTemplates();

但这显然会在 UI 线程进入睡眠状态时冻结 UI。那么任何人都可以提出一种有效的方法来处理这种情况吗?

PS:LoadTemplates() 初始化了一些 ObservableCollection 变量。如果在子线程db_task 内调用LoadTemplates(),则会引发以下错误This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread。于是就出现了线程等待的场景。

【问题讨论】:

  • 你不能使用异步和等待吗?
  • 其实函数LoadCollections是一个messenger事件。换句话说,当用户单击 UI 上的按钮时,ViewModel 会注册以调用 LoadCollections。所以我有点迷失在这种情况下如何使用 async/await。
  • 你不能使用Task.WaitAll(tasks);
  • 不能用await Task.Run()吗?

标签: c# multithreading


【解决方案1】:

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

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

根据您收到的错误消息,您似乎正在使用 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 和 await 进行设置,以便 LoadTemplates() 仅在延续完成后调用(反过来不会执行直到初始 DB 任务完成),特别是 LoadTemplates() 在首先调用 LoadCollections 的主 Dispatcher 线程中执行。

请注意,理想情况下,LoadCollections 的返回类型实际上是 Task。编译器更喜欢这个,它可以让你更好地处理可能出现的异常。但是 void 应该没问题,在处理事件处理方法时并不少见。

编辑:我还想提一下,涉及更彻底地更改代码但恕我直言更符合 async/await 模式的替代方法是简单地等待原始 db_task 然后执行“延续”语句内联(即不在任务中),或者(如果这些语句本身是长时间运行的并且应该在后台执行)仍然等待原始任务,然后也等待继续作为他们自己的任务,而不是明确地作为数据库任务。

例如(假设延续操作很简短,可以在主线程上运行):

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

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

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

【讨论】:

  • 我正在尝试使用 Dispatcher.Invoke 解决问题,正如你提到的,Dispatcher.CurrentDispatcher.Invoke(LoadTemplates, DispatcherPriority.ContextIdle);。但这似乎不起作用。你知道如何让Dispatcher.Invoke 响应辅助线程的完成吗?
  • 首先,定义“似乎不起作用”。那可能是很多不同的事情。二、为什么优先使用 ContextIdle?我的意思是,这应该可以,但是从 Normal 开始然后从那里开始怎么样。第三,虽然使用 Dispatcher 应该可以工作,但 async/await 恕我直言更简单并且生成更清晰的代码。你是这样尝试的吗?
  • 解决方案运行。谢谢!!没关系,但我收到一条警告消息:Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.你知道这意味着什么吗!
  • @user1603970:很高兴听到它现在正在工作。就警告而言,它的意思是它所说的:通常在异步方法中,执行返回任务或任务的语句时会使用await,但你有一个不使用@ 987654328@。因为您不使用await,所以它不会像按常规编写的方法那样在该点返回,而是继续执行(当然,直到它确实到达await 表达式)。
【解决方案2】:

如果我正确理解您的问题,必须首先运行 CallDB(),然后才能运行 GetDataFromMetaData 函数,最后运行 LoadTemplates。我会使用 ansy 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

    }

【讨论】:

    猜你喜欢
    • 2012-07-22
    • 2017-05-15
    • 1970-01-01
    • 2016-04-11
    • 1970-01-01
    • 1970-01-01
    • 2020-09-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多