簡體   English   中英

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

[英]How to make the parent thread wait for the child thread to complete - C#

我正在運行一個后台線程來從數據庫中獲取數據,以便當前線程(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<string> MetaStrings

GetDataFromMetaData1()GetDataFromMetaData2() -獲取2個單獨的列表,它們是MetaStrings子列表。

現在,我希望僅在加載_myList1_myList2之后(即db_task完成執行時)執行功能LoadTemplates 目前,我正在使用

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

LoadTemplates();

但這顯然會在UI線程進入睡眠狀態時凍結UI。 那么,有人可以提出一種有效的方案來應對這種情況嗎?

PS: LoadTemplates()初始化一些ObservableCollection變量。 如果在子線程db_task內調用LoadTemplates()db_task引發以下錯誤。 This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread 因此出現了線程等待的情況。

您問錯了問題。 在輔助線程上運行進程時,您永遠不要主線程等待操作完成。 那只是浪費,您最好只在主線程上運行該操作並完成操作。

因此,問題是:如何使主(父)線程處理次(子)線程的完成?

根據收到的錯誤消息,似乎您正在使用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任務已完成),尤其是要在主Dispatcher線程中執行LoadTemplates(),首先在其中調用LoadCollections。

請注意,理想情況下,LoadCollections的返回類型實際上是Task。 編譯器更喜歡這種方式,它將使您能夠更好地處理可能出現的異常。 但是void應該可以,並且在處理事件處理程序方法時並不少見。

編輯:我也想提一下,一種替代方案,涉及到更徹底地更改代碼,但是IMHO與async / await模式更加一致,要么是簡單地等待原始db_task,然后內聯執行“ 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等待,如下所示:

    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

    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM