Reputation: 15
Why does this code:
private static void UdpPortListener(UInt16 Port)
{
Console.WriteLine("Listening to port: {0}", Port);
}
static void Main(string[] args)
{
List<Thread> ts = new List<Thread>();
for(int i = 0; i < 20; i++)
{
Thread t = new Thread(() =>
{
UdpPortListener(Convert.ToUInt16(52000 + i));
});
t.IsBackground = false;
ts.Add(t);
}
ts.ForEach((x) => x.Start());
}
produce this output:
Listening to port: 52020
Listening to port: 52020
...
Listening to port: 52020
When I was writing this code I hoped it would print incrementing numbers starting from 52000
Upvotes: 1
Views: 194
Reputation: 2716
The code has 99 problems (just joking) and closure is one of them :). Also you don't need full blown threads you can use tasks.
void static Main()
{
List< System.Threading.Tasks.Task> ts = new List< System.Threading.Tasks.Task>();
for(int i = 0; i < 20; i++) // why not have i = 52000 ???
{
var num = Convert.ToUInt16(52000 + i);
var t = new System.Threading.Tasks.Task(() =>
{
UdpPortListener(num);
});
ts.Add(t);
}
ts.ForEach((x) => x.Start());
}
// Define other methods and classes here
private static void UdpPortListener(UInt16 Port)
{
Console.WriteLine("Listening to port: {0}", Port);
}
Upvotes: 1
Reputation: 65079
Its the closure you've got there that closes over your for
loop variable.
That i
variable is promoted at compile time .. because its a loop counter and its actually accessed outside of the loop (in the thread delegate here):
Thread t = new Thread(() =>
{
UdpPortListener(Convert.ToUInt16(52000 + i));
}); // ^^^ the compiler closes over this
What this means, is that by the time your Threads
are spawned up the value of i
is checked in your UdpPortListener
method ... the value of i
is the last value in the for loop.. because the loop executed before it.
To fix this .. you need to copy the value inside loop:
var temp = i;
Thread t = new Thread(() =>
{
UdpPortListener(Convert.ToUInt16(52000 + temp));
});
Upvotes: 3
Reputation: 733
This happens due to closure effect. Try this:
static void Main(string[] args)
{
List<Thread> ts = new List<Thread>();
for(int i = 0; i < 20; i++)
{
var closureIndex = i;
Thread t = new Thread(() =>
{
UdpPortListener(Convert.ToUInt16(52000 + closureIndex));
});
t.IsBackground = false;
ts.Add(t);
}
ts.ForEach((x) => x.Start());
}
Upvotes: 2