C#多线程工作,然后等待所有线程完成

C#多线程工作,然后等待所有线程完成,c#,multithreading,C#,Multithreading,我在做小型SSHClient。我有一个连接到不同计算机的客户端列表。我有一个脚本,我想在这些计算机上运行。我想在不同的线程中并行运行它。 我在这里受到启发: 以下是我的代码: int toProcess, count = 0; ManualResetEvent resetEvent = new ManualResetEvent(false); toProcess = count = clients.Count; for (int i = 0;

我在做小型SSHClient。我有一个连接到不同计算机的客户端列表。我有一个脚本,我想在这些计算机上运行。我想在不同的线程中并行运行它。 我在这里受到启发:

以下是我的代码:

 int toProcess, count = 0;
        ManualResetEvent resetEvent = new ManualResetEvent(false);
        toProcess = count = clients.Count;
        for (int i = 0; i < count; i++)
        {
                new Thread(delegate()
                {
                    var cmd = clients[i].RunCommand("./script.sh");
                    res += cmd.Result;
                    if (Interlocked.Decrement(ref toProcess) == 0)
                        resetEvent.Set();
                }).Start();
        }
        resetEvent.WaitOne();

        //do something
int-toProcess,count=0;
ManualResetEvent resetEvent=新的ManualResetEvent(错误);
toProcess=count=clients.count;
for(int i=0;i
对我来说,这个代码看起来不错。但有时(实际上在大多数情况下)会发生这样的情况:在程序正确地退出for循环后,它会正确地到达行
resetEvent.WaitOne()但之后,它不再等待所有线程完成并继续执行代码的其余部分,而是再次转到新线程(委托()…代码的一部分),因为变量i已经是2(如果客户端列表中有两个客户端),我得到一个错误:

索引超出范围。必须为非负且小于的大小 收藏

我想问的是,尽管for循环已经完成,但它如何可能创建另一个线程,以及如何避免这种情况


谢谢

在我看来,这太麻烦了。我建议使用
并行。对于

 int toProcess, count = 0;
 toProcess = count = clients.Count;
 object locker = new object();
 Parallel.For(0, count, i =>
 {
     var cmd = clients[i].RunCommand("./script.sh");
     lock(locker) res += cmd.Result;
 });

请参阅此链接:。

您可以使用并行linq查询并通过以下方法聚合其结果:


使用方法我们创建尽可能多的线程,使用Sum方法我们运行linq查询并获取每个结果进行汇总

似乎问题就在clients.Count附近。发布更多与之相关的代码为什么不使用Thread.Join?…或者您的
clients
数组已更改(来自其他线程?)在循环运行期间?TPL(任务并行库)不会使这几乎成为一个一行程序吗?捕获了变量
i
。典型的闭包问题。唯一的问题是我们不知道
cmd.Result
是什么。它可能是字符串,在这种情况下
+=
是串联的,所以不能使用
Sum()
。在这方面,我们始终可以使用聚合。
var totalResult = (from i in Enumerable.Range(0, client.Count).AsParallel()
                   let cmd = clients[i].RunCommand("./script.sh")
                   select cmd.Result).Sum();