2012-10-04 109 views
2

我想知道,當所有的線程在多線程程序等待多個後臺線程

已完成不一樣的東西彙集

while(!allThreadFinished){ 
thread.sleep(100); 
} 

的解決方案應該用監視器,但我不能我怎麼能批准它是正確的。 由於以下代碼中的「SomeMethod」使用網絡,因此會消耗時間。

public object SomeMethod(string input); 
public object[] MultiThreadMethod(string[] inputs) { 
      var result = new object[inputs.Count()]; 
      int i = 0; 
      foreach (var item in inputs) { 
       BackgroundWorker work = new BackgroundWorker(); 
       work.DoWork += (sender, doWorkEventArgs) => { doWorkEventArgs.Result = SomeMethod(item); }; 
       work.RunWorkerCompleted += (sender, runWorkerCompletedEventArgs) => { 
        result[i] = runWorkerCompletedEventArgs.Result; 
       }; 
       i++; 
       work.RunWorkerAsync(); 
      } 
      ///////////////////////////////////////////////////////////// 
      //**wait while all thread has been completed** 
      ///////////////////////////////////////////////////////////// 
      return result; 
     } 
+0

由於您使用'BackgroundWorker'一定意味着你是在GUI環境中,在這種情況下,你不應該阻止,直到他們全部完成,你應該繼續上一旦完成,只需運行一些代碼即可。要麼是這樣,要麼你不在UI環境中(或者已經在後臺線程中),在這種情況下,你不應該在這裏使用BackgroundWorker。 – Servy

+0

你的意思是使用Thread更好? – Ali

+0

嗯,這取決於。你是否在GUI環境中?此方法是否從UI線程運行?如果是這樣,你應該不會被阻止,你應該創建後臺任務,然後在完成所有代碼時執行一些代碼。如果您不在UI線程中並且確實需要阻止,那麼您應該使用'Task'而不是BackgroundWorkers(或線程)。 – Servy

回答

1

BackgroundWorker上鉤住RunWorkerCompleted事件。工作完成後它會啓動。

如何正確使用BackgroundWorker的完整示例可以在here找到。

+0

我在代碼中使用RunWorkerCompleted。 但我想知道什麼時候他們都完成了。 – Ali

3

嘗試使用TPL http://msdn.microsoft.com/en-us/library/dd460717.aspx

List<Task> tasks = new List<Task>(); 

Task t1 = new Task(() => 
{ 
    // Do something here... 

}); 
t1.Start(); 
tasks.Add(t1); 

Task t2 = new Task(() => 
{ 
    // Do something here... 

}); 
t2.Start(); 
tasks.Add(t2); 

Task.WaitAll(tasks.ToArray()); 
+1

這裏你要'Task ',而不是'Task',因爲它們每個都返回一個結果。 – Servy

+0

您的意思是任務? –

+1

嗯,是的,但是'TResult'屬於'object'類型。該方法不是通用的(雖然這可能不是一個可怕的想法)。如果您選擇讓這些任務不返回任何內容,那麼您需要讓它們全部將這些項目添加到任務主體中的集合中,並確保這樣做不會產生競爭條件。 – Servy

2

你可以使用TPL來做同樣的事情,你會避免使用Thread.Sleep(),它會更清晰。檢查了這一點:http://msdn.microsoft.com/en-us/library/dd537610.aspx

您與TPL例子是這樣的(未測試的代碼):

private ConcurrentBag<object> _results; 
    public object[] MultiThreadMethod(string[] inputs) 
    { 
     _results = new ConcurrentBag<object>(); 
     var tasks = new Task[inputs.Length]; 
     for (int i = 0; i < inputs.Length; i++) 
     { 
      tasks[i] = Task.Factory.StartNew(() => DoWork(inputs[i])); 
     } 

     Task.WaitAll(tasks); 
     return _results.ToArray(); 
    } 

    private void DoWork(string item) 
    { 
     _results.Add(SomeMethod(item)); 
    } 

編輯:沒有ConcurrentBag:

public object[] MultiThreadMethod(string[] inputs) 
    { 
     var tasks = new Task<object>[inputs.Length]; 
     for (int i = 0; i < inputs.Length; i++) 
     { 
      tasks[i] = Task<object>.Factory.StartNew(() => DoWork(inputs[i])); 
     } 

     Task.WaitAll(tasks); 
     return tasks.Select(task => task.Result).ToArray(); 
    } 

    private object DoWork(string item) 
    { 
     return SomeMethod(item); 
    } 
+0

您實際上不使用(或需要)您的併發包。 WaitAll返回每個任務結果的數組,這正是他需要的。 – Servy

+0

你是對的..編輯..;) – margabit

+0

你不需要從'tasks'數組中選擇結果。正如我所說的,'WaitAll'已經以數組形式返回結果,只是返回'WaitAll'的結果。 – Servy