2011-12-27 77 views
3

首先我是新手,所以請對我和我的英語有點耐心。 :-)帶WebRequest的C#多線程程序

我正在編寫一個C#應用程序,它應該將多線程SOAP請求發送到apache後端。 一切正常,直到現在,但我遇到了一個問題。應用程序首先從另一個系統中讀取一個XML文件 ,該文件首先被解析爲類,然後進行排序併發送到SOAP後端。 這裏摘錄

List<Thread> ThreadsPerOneRecord = new List<Thread>();   
bool ExecuteSingleThreaded = false; 
//The variable list is passed as parameter to the function 

foreach (Record prov in list) 
{ 
    XMLResult.AppendText("Type: " + prov.Type + Environment.NewLine); 

    Thread t = new Thread(() => Send(prov, c));         
    t.Start(); 
    //Here the sleep 
    Thread.Sleep(50); 
    ThreadsPerOneRecord.Add(t);    

    #region Code for test single threaded execution 
    if (ExecuteSingleThreaded) 
    { 
    foreach (Thread t2 in ThreadsPerOneRecord) 
     t2.Join(); 
    ThreadsPerOneRecord.Clear(); 
    } 
    #endregion 
} 

XMLResult.AppendText("Waiting for the threads to finish" + Environment.NewLine); 
//Waiting for the threads to finish 
foreach (Thread t in ThreadsPerOneRecord)    
    t.Join(); 

正如我送這個給它工作得很好,除了一個請求的SOAP Web服務。這些請求相互混淆。 I .: .:

What it should be: 
Record 1 -> SOAP 
Record 2 -> SOAP 
Record 3 -> SOAP 

What it is 
Record 1 -> SOAP 
Record 2 -> SOAP 
Record 2 -> SOAP 
Record 3 -> nowhere 

我已經試過調試整個代碼,並與調試器工作正常。當我插入50毫秒的睡眠時也是如此。但沒有睡眠它混合這兩個記錄...

有沒有人有任何想法,爲什麼會發生這種情況?不應該每個線程都獨立於它自己嗎? 我也檢查了收集和數據正確的裏面。

感謝

Oldfighter

+0

昨天晚上我發生了同樣的事情,所以這就是爲什麼它是我心中的新鮮:) – 2011-12-27 18:15:37

回答

4

經典的foreach /捕獲;修復很簡單 - 添加一個額外的變量:

foreach (Record tmp in list) 
{ 
    Record prov = tmp; 
  XMLResult.AppendText("Type: " + prov.Type + Environment.NewLine); 

  Thread t = new Thread(() => Send(prov, c));                       

否則,「prov」將在所有lambda表達式之間共享。已經公開提到,正在對c#5進行評估,但尚未得到確認。

+0

+1,偉大的思想都相似! – 2011-12-27 18:06:20

+0

@joe我總是去「改變循環變量的名稱」的方法 - 少(零)代碼後改變。否則很容易錯過「prov」的用法(需要更改爲新變量) – 2011-12-27 18:09:26

+0

啊,你說得對!我錯過了一些重命名。 Dang resharper讓我用來不檢查其他地方重命名 – 2011-12-27 18:11:58

6

更換

Thread t = new Thread(() => Send(prov, c)); 
t.Start(); 

Thread t = new Thread(item => Send(item, c)); 
t.Start(prov); 

在你的代碼lambda表達式實際看到改變迭代變量(這是相同的變量每個線程,當您將lambda傳遞給線程構造函數時未捕獲到值uctor)。

4

您的問題是,你在你的foreach循環

這裏訪問修改閉合的修補程序:

 List<Thread> ThreadsPerOneRecord = new List<Thread>(); 
     bool ExecuteSingleThreaded = false; 
     //The variable list is passed as parameter to the function 

     foreach (Record prov in list) 
     { 
      var tempProv = prov; 
      XMLResult.AppendText("Type: " + tempProv.Type + Environment.NewLine); 

      Thread t = new Thread(() => Send(tempProv, c)); 
      t.Start(); 
      //Here the sleep 
      Thread.Sleep(50); 
      ThreadsPerOneRecord.Add(t); 

      #region Code for test single threaded execution 
      if (ExecuteSingleThreaded) 
      { 
       foreach (Thread t2 in ThreadsPerOneRecord) 
        t2.Join(); 
       ThreadsPerOneRecord.Clear(); 
      } 
      #endregion 
     } 

     XMLResult.AppendText("Waiting for the threads to finish" + Environment.NewLine); 
     //Waiting for the threads to finish 
     foreach (Thread t in ThreadsPerOneRecord) 
      t.Join();