2012-10-07 118 views
2

我正在處理小SSHClient。我有一個連接到不同計算機的客戶端列表。我有一個腳本,我想在這些計算機上運行。我想在不同的線程中並行運行它。 我來到這裏的啓發: Stackoverflow - threadsC#多線程的工作,然後等到所有完成

這裏是我的一段代碼:

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 

對我來說,這個代碼看起來OK。但有時(實際上在大多數情況下),它發生在程序正確退出for循環後,它會正確地到達resetEvent.WaitOne();行,但之後,而不是等待所有線程完成並繼續執行其餘代碼,再次進入新的Thread(委託()...代碼的一部分,因爲變量i已經是2(如果有在客戶端列表中兩個客戶端)我得到一個錯誤:

Index was out of range. Must be non-negative and less than the size of the collection.

我想問問它是如何可能的,它創建另一個線程雖然for循環結束了。而如何避免?

謝謝

+0

似乎這個問題是靠近clients.Count。發佈更多相關的代碼 – Regfor

+2

爲什麼你不使用Thread.Join? – Vlad

+0

那麼,你確定你的代碼不是外部循環的一部分或不再被調用嗎?你也許應該在函數的開始處使用斷點。 – Vlad

回答

3

這在我看來很混亂。我建議使用Parallel.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; 
}); 

請參閱此鏈接:Parallel.For

+0

太好了,謝謝。 – Kubik

+0

@Kubik:沒問題。如果解決了您的問題,您可以將答案標記爲已接受。 – Tudor

0

您可以使用並行LINQ查詢,並通過Sum方法整合其結果:

var totalResult = (from i in Enumerable.Range(0, client.Count).AsParallel() 
        let cmd = clients[i].RunCommand("./script.sh") 
        select cmd.Result).Sum(); 

隨着AsParallel方法,我們創造儘可能多的線程,我們可以與求和方法,我們運行LINQ查詢,並獲取每個結果總結起來

+0

唯一的問題是我們不知道'cmd.Result'是什麼。在這種情況下'+ ='是串聯的,所以你不能使用Sum()'。 – Tudor

+0

對於這個問題,我們總是可以使用Aggregate。 http://msdn.microsoft.com/en-us/library/system.linq.enumerable.aggregate.aspx – zahir

相關問題