.NET Framework 4からサポートされるParallel.ForEachと同じようなメソッドを、ThreadPool.QueueUserWorkItemメソッドを使って実装する。

using System;
using System.Collections.Generic;
#if LINQ
using System.Linq;
#endif
using System.Threading;

public static class Parallel {
  public static void ForEach<TSource>(/*this*/ IEnumerable<TSource> enumerable, Action<TSource> action)
  {
    if (enumerable == null)
      throw new ArgumentNullException("enumerable");

#if LINQ
    var count = enumerable.Count();
#else
    var count = 0;

    if (enumerable is System.Collections.ICollection) {
      count = (enumerable as System.Collections.ICollection).Count;
    }
    else {
      var enumerator = enumerable.GetEnumerator();

      while (enumerator.MoveNext())
        count++;
    }
#endif

    if (count == 0)
      return;
    else if (action == null)
      throw new ArgumentNullException("action");

    using (var wait = new AutoResetEvent(false)) {
      foreach (var e in enumerable) {
        ThreadPool.QueueUserWorkItem(delegate(object state) {
          try {
            action((TSource)state);
          }
          finally {
            if (Interlocked.Decrement(ref count) == 0)
              wait.Set();
          }
        }, e);
      }

      wait.WaitOne();
    }
  }
}

§1 サンプルと実行例

public class Test {
  static void Main(string[] args)
  {
    Console.WriteLine("Environment.ProcessorCount: {0}", Environment.ProcessorCount);

    int maxWorkerThreads, maxCompletionPortThreads;

    ThreadPool.GetMaxThreads(out maxWorkerThreads, out maxCompletionPortThreads);

    Console.WriteLine("maxWorkerThreads: {0}", maxWorkerThreads);
    Console.WriteLine("maxCompletionPortThreads: {0}", maxCompletionPortThreads);
    Console.WriteLine();

    Parallel.ForEach(new[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, delegate(int i) {
      Console.WriteLine("started {0}", i);
      Thread.Sleep((new Random(unchecked((int)(Environment.TickCount * i)))).Next(5, 25) * 200);
      Console.WriteLine("finished {0}", i);
    });

    Console.WriteLine("done");
  }
}
環境1: Ubuntu 9.04 + Mono プロセッサ数=2
$ gmcs pfe.cs -define:LINQ && mono pfe.exe
Environment.ProcessorCount: 2
maxWorkerThreads: 40
maxCompletionPortThreads: 20

started 1
started 0
started 2
started 3
started 4
started 9
started 5
started 6
started 7
started 8
finished 4
finished 6
finished 2
finished 5
finished 8
finished 1
finished 7
finished 3
finished 0
finished 9
done
環境2: Windows XP + .NET Framework プロセッサ数=1
D:\>csc pfe.cs -define:LINQ && pfe.exe
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.1
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.

Environment.ProcessorCount: 1
maxWorkerThreads: 250
maxCompletionPortThreads: 1000

started 0
started 1
started 2
started 3
started 4
started 5
started 6
finished 0
started 7
finished 1
started 8
started 9
finished 3
finished 4
finished 2
finished 9
finished 7
finished 8
finished 5
finished 6
done