[英]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.