The problem here is that your thread is reading the state of the loop from the lambda expression, within the new thread, rather than passing the actual values over to the thread.
This means that by the time the new thread gets scheduled on the CPU, the loop has actually iterated forward to an unknown state. This is why your values appear random.
Here's what's happening in a step by step:
- The
() => sendComThread(IP, com) lambda is created, which references the two parameters. theThreads[i].Start(); is called, but this does not guarantee that the code in that thread will immediately run. It is likely that the current code will continue for a while before the thread scheduler on the system switches the context to a different thread. - The next loop iteration occurs and
IP = item.ToString(); is executed, changing the value of IP. This may occur more than once. - The context switch occurs on the processor and the other thread is executed, or the other thread executes on another processor (core), reading the reference to
IP from the lambda expression. - This causes a cross-thread read, meaning that the state of
IP is undefined.
The solution is to pass the values over during thread creation, so that they are copied local to the thread:
struct SendComThreadParams { public string IP; public string Com; public SendComThreadParams(string ip, string com) { this.IP = ip; this.Com = com; } } private void sendCom(String com) { //send command to selected item int i=0; String IP; foreach (var item in checkedListBox1.CheckedItems) { Console.WriteLine(item.ToString()); IP = item.ToString(); theThreads[i] = new Thread(new ParameterizedThreadStart(sendComThread)); theThreads[i].Start(new SendComThreadParams(IP, com)); i++; } } private void sendComThread(object threadParam) { var p = (SendComThreadParams)threadParam; // send an command System.Console.WriteLine(p.IP + p.Com); }
This properly copies the parameters over to the thread, such that their values are guaranteed to be in a defined state.