Question

In my application I have a set number of actions to preform. I want to designate a specific amount of threads to do the actions. As some action may take longer than others and can be waiting for a response, when the thread finishes I want it to go back to the queue and start the next action. So, as one of the ten threads free up, it gets a new action, so on and so forth until the queue is empty then continue. I need to wait for all the actions to complete before continuing.

So I did some research and testing using TPL which was working great before remembering, "oh crap, I am limited to .Net 2.0 in this application". I've trying to rebuild using only .Net 2.0 but am having no luck. I have virtually no experience with Threading.

Can anyone help me convert this logic into .Net 2.0?

List<int> results = new List<int>();
var stopwatch = Stopwatch.StartNew();

Random random = new Random();
using (BlockingCollection<Action> queue = new BlockingCollection<Action>())
{
    for (int i = 0; i < 20; i++)
    {
        int index = i;
        queue.Add(delegate
                      {

                          int foo = random.Next(1, 1500);
                          Thread.Sleep(foo);
                          results.Add(foo);
                          Debug.WriteLine(index + " Working: " + foo + " " + Task.CurrentId);
                      });
    }
    queue.CompleteAdding();

    const int numWorkers = 10;
    Task[] tasks = new Task[numWorkers];
    for (int i = 0; i < numWorkers; i++)
    {
        tasks[i] = Task.Factory.StartNew(() =>
                                             {
                                                 foreach (Action action in queue.GetConsumingEnumerable())
                                                 {
                                                     action();
                                                 }
                                             }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
    }
    Task.WaitAll(tasks);
}
Debug.WriteLine("WaitAll took {0} seconds", stopwatch.Elapsed.TotalSeconds);
Was it helpful?

Solution

I'm going to outline how I did this a while ago:

  1. Create N threads
  2. Put the work items into a list of known size
  3. Have a shared variable int lastIndex = -1;
  4. Have all the threads do this:

    while(true) {
        var index = Interlocked.Increment(ref lastIndex);
        if (index >= list.Count) return;
        ProcessItem(list[index]);
    }
    

Very simple.

Abstract all of this away into a helper method. It should take a delegate so that you don't need to hard-code ProcessItem.

This helper is actually useful even for .NET 4.5 in cases where you need guaranteed exact degree of parallelism which the thread-pool does not provide.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top