为什么这段代码:
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());
}
产生这个输出:
Listening to port: 52020
Listening to port: 52020
...
Listening to port: 52020
当我编写这段代码时,我希望它能打印从52000开始递增的数字
答案 0 :(得分:3)
它已经关闭了你的for
循环变量。
在编译时提升i
变量..因为它是一个循环计数器,它实际上是在循环之外访问的(在这里的线程委托中):
Thread t = new Thread(() =>
{
UdpPortListener(Convert.ToUInt16(52000 + i));
}); // ^^^ the compiler closes over this
这意味着,当您的Threads
产生时,i
方法会检查UdpPortListener
的值... i
的值for循环中的最后一个值..因为循环在它之前执行。
要修复此问题,您需要复制循环内的值:
var temp = i;
Thread t = new Thread(() =>
{
UdpPortListener(Convert.ToUInt16(52000 + temp));
});
答案 1 :(得分:2)
这是由于封闭效应造成的。试试这个:
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());
}
答案 2 :(得分:1)
代码有99个问题(只是开玩笑),封闭就是其中之一:)。此外,您不需要完整的线程,您可以使用任务。
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);
}