【问题标题】:C# multi-threading program with WebRequest带有 WebRequest 的 C# 多线程程序
【发布时间】:2011-12-27 17:56:47
【问题描述】:

首先我是论坛的新手,所以请对我和我的英语有一点耐心。 :-)

我正在编写一个 C# 应用程序,它应该将多线程 SOAP 请求发送到 apache 后端。 到目前为止一切正常,但我遇到了问题。应用程序首先读取一个 XML 文件 来自另一个系统,该系统首先被解析为类,排序并发送到 SOAP 后端。 这里是sn-p

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 服务时,它工作正常,除了一个请求。这些请求相互混淆。即:

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 毫秒的睡眠时也是如此。但是没有睡眠它混合了这两个记录......

有人知道为什么会这样吗?每个线程不应该独立于自身吗? 我还检查了集合,数据在里面是正确的。

谢谢

老战士

【问题讨论】:

  • 昨晚我也发生了同样的事情,所以这就是为什么它让我记忆犹新:)

标签: c# xml multithreading soap thread-safety


【解决方案1】:

替换

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

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

在您的代码中,lambda 表达式实际上会看到迭代器变量的变化(对于每个线程来说,它都是同一个变量,而不是在您将 lambda 传递给线程构造函数时捕获的值)。

【讨论】:

    【解决方案2】:

    经典的 foreach/capture;修复很简单——添加一个额外的变量:

    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 评估修复此问题,但尚未确认任何一种方式。

    【讨论】:

    • @joe 我总是选择“更改循环变量的名称”方法 - 之后更改的代码更少(零)。否则很容易错过“prov”的用法(需要将其更改为新变量)
    • 啊,你是对的!我错过了一些重命名。 Dang resharper 让我习惯于不检查其他要重命名的位置
    【解决方案3】:

    您的问题是您正在访问 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(); 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-24
      • 2010-12-01
      • 2010-12-14
      相关资源
      最近更新 更多