C# 多线程程序与WebRequest

发布于 2024-12-23 12:52:26 字数 1450 浏览 0 评论 0原文

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

我正在编写一个 C# 应用程序,它应该向 apache 后端发送多线程 SOAP 请求。 到目前为止一切都很好,但我遇到了问题。应用程序首先读取一个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 服务时,除了一个请求之外,它工作正常。这些请求彼此混合。即:

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

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

谢谢

老战士

First I am new in the forum so please have a little bit patience with me and my english. :-)

I am writing a C# application which should send multithreaded SOAP requests to an apache backend.
Everything worked fine till now but I ran into a problem. The application first reads a XML file
from another system that is parsed first into classes, sorted and send to the SOAP backend.
Here the snippet

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(); 

As I am sending this to the SOAP web service it works fine except one request. These requests are mixed up between each other. I.e.:

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

I already tried to debug the whole code and with the debugger it works fine. The same when I insert this sleep of 50 milliseconds. But without the sleep it mixes this two records ...

Does anybody have any idea why this happens? Shouldn't every thread be independent from itself?
Also I checked the collection and the data are correctly inside.

Thanks

Oldfighter

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

愿得七秒忆 2024-12-30 12:52:26

替换

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

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

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

Replace

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

with

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

In your code lambda expression actually sees changes to iterator variable (it's the same variable for every thread, not value captured when you passed lambda to thread constructor).

梅倚清风 2024-12-30 12:52:26

经典的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 评估修复此问题,但尚未得到证实。

Classic foreach/capture; fix is easy - add an extra variable:

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

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

Otherwise, "prov" is shared between all the lambdas. It has been publicly mentioned that fixing this is being evaluated for c# 5, but not yet confirmed either way.

吾性傲以野 2024-12-30 12:52:26

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

your problem is that you are accessing a modified closure in your Foreach loop

here is the fix:

        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(); 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文