简体   繁体   中英

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(); line of code. Please, any ideas how to fix it?

Ah, good ol' closure over the iterator variable ;p

Move the 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 :

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.

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. 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 ". 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM