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. Ie:
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
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).
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();
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.