2

Note that in the locals i = 3

As you can clearly see the highest index of the args[] is 2, however the iterator somehow gets to 3. Explanation?

Edit: The commented Thread.Sleep magically fixes the problem.

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
TheDespite
  • 333
  • 1
  • 2
  • 11
  • 2
    Anything is possible with code that is not thread safe ... – Brian Rasmussen Apr 09 '14 at 00:38
  • there are two threads if i am not mistaken...the main thread and temp...the main thread controls the for loop..and temp[] controls the string array...the `Thread.Sleep(1)` fixes the problem by forcing the main thread to sleep for 1 millisecond..i am i right? – HackerMan Apr 09 '14 at 00:41
  • You should remove your extra thread and verify you get the exception. Thread testing 101! – Erik Philips Apr 09 '14 at 00:45
  • This is a matter of the lambda capturing the index, `i`. It has little to do with threads. – John Saunders Apr 09 '14 at 00:46

2 Answers2

6

This is caused by i being declared outside of the for loop, for the entire for loop. Since there is no guarantee that the Thread is executed at that point, the value of i can change before the Thread executes. You can "resolve" this by declaring a local variable in the for loop.

//for loop ..
var localIndex = i;
var temp = new Thread(() => PrintOut(args[localIndex], IsFilePath(args[localIndex])));
temp.Start();
//for loop ..

EDIT: Also, can you please post a code snippet next time, saves me having to write out the code again :P

Xenolightning
  • 4,140
  • 1
  • 26
  • 34
  • 1
    Right, the `for` loop's incrementor (`i++`) executes before the body of the thread is invoked. Thus, `i` can be incremented to `3` before the thread actually runs. – Kirk Woll Apr 09 '14 at 00:47
  • Always thought the call to Thread.Start actually starts the thread. "Once a thread is in the ThreadState.Running state, the operating system can schedule it for execution." http://msdn.microsoft.com/en-us/library/6x4c42hc%28v=vs.110%29.aspx – TheDespite Apr 09 '14 at 02:16
1

First of all

for (var i = 0; i< args.Length; i++)
{
}

is equivalent to:

int i = 0;

loop:

if (i < args.Length)
{
    i++;
    goto loop;
}

so you see that i is incremented to 3 in order to check your condition.

Of course, new Thread(() => PrintOut(args[i], IsFilePath(args[i]))) is never actually called when i is 3. However, since there is only one instance of i which the loop changes on each iteration, the execution that started when i was 2 is affected when i is incremented to 3.

To fix this, you need to copy the value of i into a new variable on each loop iteration. This copy will not be updated by the for loop:

for (var i = 0; i< args.Length; i++)
{
     var copy = i;
     Thread temp = new Thread(() => PrintOut(args[copy], IsFilePath(args[copy]))
}
Gustavo Mori
  • 8,319
  • 3
  • 38
  • 52
Martin Booth
  • 8,485
  • 31
  • 31