Search code examples
c#.net-3.5manualresetevent

Parallel programming with ManualResetEvent


I have one method to handle a List<string> parallel. Unfortunately I can't use .NET 4+.

But when I run this method, i is always items.Count

public static void ParallelForEachTest(List<string> items)
{
    if (items != null && items.Count > 0)
    {
        List<ManualResetEvent> mEventList = new List<ManualResetEvent>();
        for (int i = 0; i < items.Count ; i++)
        {
            ManualResetEvent mEvent = new ManualResetEvent(false);
            ThreadPool.QueueUserWorkItem((y) =>
            {
                Console.WriteLine(items[i] + i);
                mEvent.Set();
            });
            mEventList.Add(mEvent);
        }
        mEventList.ForEach(x => x.WaitOne());
    }
}

What do I need to change to achieve

x 0
x 1
x 2

for ParallelForEachTest(new List<string>(){"x","x","x"});


Solution

  • At the time when Console.WriteLine is executed, loop has already terminated and loop variable i has its final value, which is equal to list.Count.

    In order to have each task print its corresponding index, you have to pass the index value to the task itself:

    ThreadPool.QueueUserWorkItem((y) => { ... }, i);
    

    The second argument is the state that will be passed to the callback once the task is started.

    Also, make sure not to use closure to access state from inside the task. Only use task state to transfer data:

    public static void ParallelForEachTest(List<string> items)
    {
        if (items != null && items.Count > 0)
        {
            List<ManualResetEvent> mEventList = new List<ManualResetEvent>();
            for (int i = 0; i < items.Count; i++)
            {
                ManualResetEvent mEvent = new ManualResetEvent(false);
                ThreadPool.QueueUserWorkItem(
                    (state) =>
                    {
                        Tuple<string, int, ManualResetEvent> tuple =
                            (Tuple<string, int, ManualResetEvent>)state;
                        Console.WriteLine(tuple.Item1 + tuple.Item2);
                        tuple.Item3.Set();
                    },
                    Tuple.Create(items[i], i, mEvent));
                mEventList.Add(mEvent);
            }
            mEventList.ForEach(x => x.WaitOne());
        }
    }