Update 19.June.2020: Alexei Levenkov suggested Captured variable in a loop in C# - my issue may have nothing to do with threading. I've been using C# for almost 20 years and never knew this and have never knowingly been affected by it. Now I'm a little worried about everything that I've ever done...Thanks Alexei!
I have some C# code that creates threads to pass parameters to a method to page through some data. One of those parameters to the method is the counter for the loop that creates the threads.
Using Console.WriteLine(), I can see that the value to pass to the method is 0 on the first iteration, but the method receives 100, which is the value of the increment for the loop, as if it's receiving the value after the subsequent iteration of the loop or the iterations are sharing a framestack or whatever somehow. It seems impossible because skup is just a value type int.
I do not have this problem when Repository.Configuration.UseThreading is false.
I am not very familiar with threading, so I wonder what I have told it to do that could cause this. I tried creating an Int32 from skip just to pass to the method but had the same result. Whatever the issue is, it's hard for me to understand the consequences where I pass other parameters.
The first thing the method in the thread does is show the value that it recives, which is 100:
private void LoadBatch(EntryPointer entryPointer, ContentTypeWrapper contentTypeWrapper,
int skip, Action<EntryPointer> action)
{
Console.WriteLine("LoadBatch: " + skip);
//...
Here is the code that creates the threads:
foreach (ContentTypeWrapper contentTypeWrapper in contentTypeWrappers)
{
if (contentTypeWrapper.EntriesLoaded == contentTypeWrapper.EntryCount)
{
Repository.Instrument.Warn(this, $"contentTypeWrapper.ContentTypeUid"
+ $" already loaded or {contentTypeWrapper.EntryCount} entries; skip");
continue;
}
for (int skip = 0; skip < contentTypeWrapper.EntryCount;
skip += Repository.Configuration.QueryLimit)
{
if (Repository.Configuration.UseThreading)
{
new Thread(() => LoadBatch(entryPointer, contentTypeWrapper, skip, action))
.Start();
}
else
{
LoadBatch(entryPointer, contentTypeWrapper, skip, action);
}
}
If I make this change, it works the way that I would expect:
for (int skip = 0; skip < contentTypeWrapper.EntryCount;
skip += Repository.Configuration.QueryLimit)
{
int mySkip = skip;
if (Repository.Configuration.UseThreading)
{
Console.WriteLine("Passing to LoadBatch: " + mySkip);
new Thread(() => LoadBatch(entryPointer, contentTypeWrapper, mySkip, action))
.Start();