[英]Closure lambda expression in C#
I have this kind of function. 我有这种功能。
function SomeFunction()
{
const int NUMBER_OF_CONCURENT_THREADS = 50;
List<Guid> sessions = new List<Guid>();
ManualResetEvent[] doneEvents = new ManualResetEvent[NUMBER_OF_CONCURENT_THREADS];
Action<int> makeServiceCall = (iter) =>
{
var proxy = GetProxy();
sessions.Add(proxy.GetCurrentSessionId());
doneEvents[iter].Set();
};
for (int i = 0; i < NUMBER_OF_CONCURENT_THREADS; ++i)
{
doneEvents[i] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem((o) =>
{
int iter = i;
makeServiceCall(iter);
});
}
WaitHandle.WaitAll(doneEvents);
Assert.AreEqual(50, sessions.Count);
}
The problem is that I am getting IndexOutOfRangeException
when at doneEvents[iter].Set();
问题是我在
doneEvents[iter].Set();
时遇到了IndexOutOfRangeException
doneEvents[iter].Set();
line of code. 代码行。 Please, any ideas how to fix it?
请问,任何想法如何解决?
Ah, good ol' closure over the iterator variable ;p 啊,关于迭代器变量的好'闭合'; p
Move the int iter
: 移动
int iter
:
int iter = i;
ThreadPool.QueueUserWorkItem((o) => {
makeServiceCall(iter);
});
Currently you are capturing something that is changing with the loop, and will usually be after the loop by the time the threads kick in. Alternatively, use the arg o
: 目前,您正在捕获随循环而变化的内容,并且通常在循环之后到线程启动时。或者,使用arg
o
:
ThreadPool.QueueUserWorkItem((o) => {
int iter = (int)o;
makeServiceCall(iter);
}, i);
This passes a boxed copy of i
at the time the item is queued, so it won't change. 这会在项目排队时传递
i
的盒装副本,因此不会更改。
In case the issue isn't clear: variables that are captured into a lambda retain their original declaration point - it is a full lexical closure. 如果问题不明确:捕获到lambda中的变量保留其原始声明点 - 它是一个完整的词法闭包。 The
i
inside QueueUserWorkItem
is not "the value of i
at the time this lambda was created", but rather, is "the value of i
now ". QueueUserWorkItem
的i
不是“创建此lambda时i
的值”,而是“ i
现在的值”。 In most cases, the for
loop will out-pace thread-creation/pickup by a massive margin, so by the time the threads have started the for
loop has finished and the value of i
is now out of bounds for the array. 在大多数情况下,
for
循环将以大幅度超出线程创建/拾取速度,因此在线程启动时, for
循环已经完成,并且i
的值现在超出了数组的范围。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.