2015-12-09 24 views
3

我已經試過這...C#等到所有的線程執行完畢

public ArrayList GetAllObjectAttributes() 
    { 
     List<Task> taskList = new List<Task>(); 
     ArrayList allObjectAttributes = new ArrayList(); 
     taskList.Add(Task.Factory.StartNew(() => { allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.Folder));})); 
     taskList.Add(Task.Factory.StartNew(() => { allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.XMLFile)); })); 
     taskList.Add(Task.Factory.StartNew(() => { allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.TextFile)); })); 
     taskList.Add(Task.Factory.StartNew(() => { allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.Parent)); })); 
     Task.WaitAll(taskList.ToArray()); 
     return allObjectAttributes; 
    } 

這...

public ArrayList GetAllObjectAttributes() 
    { 
     Thread[] threads = new Thread[4]; 
     ArrayList allObjectAttributes = new ArrayList(); 
     threads[0] = new Thread(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.Folder))); 
     threads[1] = new Thread(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.XMLFile))); 
     threads[2] = new Thread(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.TextFile))); 
     threads[3] = new Thread(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.Parent))); 

     foreach(Thread thread in threads) 
     { 
      thread.Start(); 
      thread.Join(); 
     } 
     return allObjectAttributes; 
    } 

這也太...

public ArrayList GetAllObjectAttributes() 
    { 
     Thread[] threads = new Thread[4]; 
     ArrayList allObjectAttributes = new ArrayList(); 
     threads[0] = new Thread(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.Folder))); 
     threads[1] = new Thread(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.XMLFile))); 
     threads[2] = new Thread(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.TextFile))); 
     threads[3] = new Thread(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.Parent))); 

     foreach(Thread thread in threads) 
     { 
      thread.Start(); 
     } 
     while(threads[0].IsAlive || threads[1].IsAlive || threads[2].IsAlive || threads[3].IsAlive) 
     { 
      Thread.Sleep(500); 
     } 
     return allObjectAttributes; 
    } 

我也試過 Spawn Multiple Threads for work then wait until all finished

我仍然在allObjectAttributes中的一個arraylist項目中獲得null。

然而,當我做

public ArrayList GetAllObjectAttributes() 
    { 
     ArrayList allObjectAttributes = new ArrayList(); 
     allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.Folder))); 
     allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.XMLFile))); 
     allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.TextFile))); 
     allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.Parent))); 
     return allObjectAttributes; 
    } 

我從來沒有在ArrayList的項目得到一個空項。

  1. 我在做什麼錯等到所有線程完成?
  2. 任何其他建議,以便所有4個線程完成執行後僅返回arraylist。
 
private List GetObjectAttributes(TreeViewAttrs tv) 
{ 
    List objectAttributes = new List(); 
    string command = "COMMAND_TO_EXECUTE"; 
    if (command != "") 
    { 
     List results = RunCommand(command); 
     if (results == null) { return null; } 
     if (results.Count > 0) 
     { 
      foreach (string result in results) 
      { 
       if (!result.Contains("" + tv + "")) 
       { 
        string[] res = reformatResponseString(result); //reformat the strings as per custom structure 
        if (res != null) { objectAttributes.Add(res); } 
       } 
      } 
      return objectAttributes; 
     } 
    } 
    return null; 
} 
+2

從多線程中改變一個共享的,非線程安全的實例(在你的情況下是'ArrayList')是一個非常糟糕的主意。只需使用'ConcurrentBag ',或者如果你使用.NET 4.5,則使用'Task.WhenAll',它實際上會產生一系列任務結果。 –

+0

任何人都可以幫助格式化我的問題的最後一段嗎?我試着用4個空格格式化它(正如我在早上做的那樣),但它不起作用。好像我今天錯過了很多東西。大聲笑 –

+1

你*肯定*有空傳播的地方的問題。最有可能的是一個種族或一個'ThreadStatic'或'ThreadLocal'變量隱藏在調用樹的更深處。雖然我發現'GetObjectAttributes'的發佈定義沒有任何錯誤 - 該函數看起來很純粹,所以我會查看'RunCommand'和'reformatResponseString' - 但這是一個練習。只要在你的執行鏈上的'if(something == null)'創建一些條件斷點並在調試器下運行 - 遲早你會發現你的罪魁禍首。 –

回答

7

通過使用一個線程安全的集合(.NET 4.0兼容)稍微改進:

List<Task> taskList = new List<Task>(); 
ConcurrentBag<object> allObjectAttributes = new ConcurrentBag<object>(); 

taskList.Add(Task.Factory.StartNew(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.Folder)))); 
taskList.Add(Task.Factory.StartNew(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.XMLFile)))); 
taskList.Add(Task.Factory.StartNew(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.TextFile)))); 
taskList.Add(Task.Factory.StartNew(() => allObjectAttributes.Add(GetObjectAttributes(TreeViewAttrs.Parent)))); 

Task.WaitAll(taskList.ToArray()); 

return allObjectAttributes; 

替代做法:使用Task.Result一旦所有任務都已完成,(線程安全的集合不再需要因爲只有一個線程修改ArrayList):

Task<object>[] taskList = { 
    Task.Factory.StartNew(() => (object)GetObjectAttributes(TreeViewAttrs.Folder)), 
    Task.Factory.StartNew(() => (object)GetObjectAttributes(TreeViewAttrs.XMLFile)), 
    Task.Factory.StartNew(() => (object)GetObjectAttributes(TreeViewAttrs.TextFile)), 
    Task.Factory.StartNew(() => (object)GetObjectAttributes(TreeViewAttrs.Parent)) 
}; 

Task.WaitAll(taskList); 

ArrayList allObjectAttributes = new ArrayList(); 

foreach (Task<object> task in taskList) { 
    allObjectAttributes.Add(task.Result); 
} 

return allObjectAttributes; 

值得注意的是使用Task.WhenAll改善(.NET 4.5只):

object[] allObjectAttributes = await Task.WhenAll(
    Task.Run(() => GetObjectAttributes(TreeViewAttrs.Folder)), 
    Task.Run(() => GetObjectAttributes(TreeViewAttrs.XMLFile)), 
    Task.Run(() => GetObjectAttributes(TreeViewAttrs.TextFile)), 
    Task.Run(() => GetObjectAttributes(TreeViewAttrs.Parent)) 
); 

return allObjectAttributes; 

*注:我用object作爲泛型參數爲你留下的GetObjectAttributes未指定的返回類型。

+2

我同意'Task.WhenAll'是這裏最好的選擇。 –

+0

我嘗試使用ConcurrentBag,並仍然在響應中得到空值。方法返回列表。我嘗試了很多選擇,但仍然有些結果在返回的包中爲null。但是如果我沒有線程的話,它們都不會返回null。 不知道我失蹤的地方。我會不斷嘗試今天和明天,並更新此主題。我不會離開這個,直到我得到預期的結果。 謝謝你的寶貴時間和反饋。 –

+0

@VinaySathyanarayana,在這種情況下,我怪'GetObjectAttributes' - 必須有一個競賽,它阻止它在並行調用時產生預期的結果。 –

0

您在第一個示例中使用的Task.WaitAll()應該按預期工作。但是,我懷疑你遇到的問題必須更多地使用ArrayList的線程安全性,而不是等待所有任務完成。 ArrayList不提供線程安全性,所以您應該查看其他方法,可以使用鎖定機制,也可以使用線程安全集合(如ConcurrentBag(https://msdn.microsoft.com/en-us/library/dd381779(v=vs.110).aspx))。

相關問題