pet*_*lex 2 c# lambda closures
我有这种功能.
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);
}
Run Code Online (Sandbox Code Playgroud)
问题是我IndexOutOfRangeException在doneEvents[iter].Set();代码行时得到了.请问,任何想法如何解决?
啊,关于迭代器变量的好'闭合'; p
移动int iter:
int iter = i;
ThreadPool.QueueUserWorkItem((o) => {
makeServiceCall(iter);
});
Run Code Online (Sandbox Code Playgroud)
目前,您正在捕获随循环而变化的内容,并且通常在循环之后到线程启动时.或者,使用arg o:
ThreadPool.QueueUserWorkItem((o) => {
int iter = (int)o;
makeServiceCall(iter);
}, i);
Run Code Online (Sandbox Code Playgroud)
这会i在项目排队时传递一个盒装副本,因此不会更改.
如果问题不明确:捕获到lambda中的变量保留其原始声明点 - 它是一个完整的词法闭包.在i里面QueueUserWorkItem是不是"的价值i在当时这拉姆达被创造",而是为"的价值i ,现在 ".在大多数情况下,for循环将超出线程创建/拾取的大量余量,因此在线程启动时for循环已完成且值i现在超出阵列的界限.