2012-10-04 81 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