2

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?

1

1 Answer 1

10

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.