2011-12-27 45 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();