Home > Blockchain >  For loop incrementing to thread assignment
For loop incrementing to thread assignment

Time:12-06

Been working on a program recently and have a question about a problem I ran into. I've solved it, but don't know why it's happening:

for(int i = 0; i<10; i  )
{
Thread t = new Thread (() => {(does stuff, uses "i")});
}

Essentially I have 10 known processes I want to run on separate threads. In the thread, the value of the incrementor "i" is used to assign an object to a position in another array (I use locking). Now if I run it as is, I get an out of bounds error and when I debug with code breaks, I find that on that last loop i is equal to 10, when the last value should be 9. When this code isn't threaded, it works perfectly fine.

I decided to try and assign the incrementer to a local variable inside the thread:

for(int i = 0; i<10; i  )
{
    Thread t = new Thread (() => 
    {
       localI=i;
       (does stuff, uses "localI")
    });
}

This had the same issue. I did more reading online and tried a different ordering of it:

for(int i = 0; i<10; i  )
{
    localI=i;
    Thread t = new Thread (() => 
    {
       (does stuff, uses "localI")
    });
}

And this code works. I can't at all figure out why this works, but the second example didn't. Could anyone help me figure it out?

Thanks

CodePudding user response:

Effectively there are 11 threads, your main thread running the for loop and the threads you spawn.

By the time your 10 new threads run the main loop might well be finished and the value of i will be 10. If you then use this to index an array you will get the out of bounds error.

Your third example assigns i to the localI var, this will keep its value and the individual threads will use that saved value of localI.

CodePudding user response:

It`s simple. The i variable is run on main thread and for loop reaches 10 value even before the child thread initiates. So, you can add a local variable outside of child threads to get fixed value on every loop. And, for loop set 10 on i variable, but not run loop, because gets false on checks.

Simple test:

class Program
{
    static void Main(string[] args)
    {
        Test c = new Test();
        Console.WriteLine("NonLocal:");
        Console.WriteLine(string.Join(",", c.NonLocal));
        Console.WriteLine();
        Console.WriteLine("Local:");
        Console.WriteLine(string.Join(",", c.Local));
        Console.ReadLine();
    }
}

class Test
{
    public object locker;
    public List<object> NonLocal; // use List<> for dynamic array
    public object[] Local; 

    public Test()
    {
        this.locker = new object();
        this.NonLocal = new List<object>();
        this.Local = new object[10];
  
        // child thread pool
        List<Thread> threads = new List<Thread>();

        for (int i = 0; i < 10; i  )
        {
            int localI = i;
            Thread t = new Thread(() =>
            {
                lock (locker)
                {
                    // adding to result only index
                    // to see value on i variable on this point
                    this.NonLocal.Add(i);
                    
                    // using a fixed local variable
                    this.Local[localI] = localI;
                }
            });
            threads.Add(t);
            t.Start(); 
        }

        // wait until threads end
        while (true)
        {
            if (!threads.Any(x => x.IsAlive)) break;
        }
    }
}
</code>
  • Related