Hi,
What is the nature of the work being done? you say each thread is calling the same method, but is it calling the same method with different parameters?
I ask this because I have implemented somewhat similar solutions in the past, where an array of threads consumes work from a queue.
The basic structure is that you build an array of (say 10) threads, and initialize each of these to the same method. The common method gets the parameters for it's work off a FIFO queue, does the work, then loops round to consume the next task. When all ten threads are initiated to the same queue, the work will be done simultaneously as long as there is a job for each thread.
You need to implement some locking to ensure that two threads cannot consume the same task. Also, to stop the threads thrashing away without any work to be done, you need to have them wait on an event before checking the queue for work.
You can design in events to be raised when a thread completes a task, and/or when the queue becomes empty.
This is basically the .NET thread-pool, but sometimes if you are doing some very specific work it can pay to develop your own version, where you have complete control and you are not passing delegates for each task(which takes additional overhead, and can cost some additional CPU cycles)
Here is a quick and dirty example of what I am talking about: (please note I haven't actually compiled this code it might not be 100%, but I have used this sort of pattern numerous times in the past, the concept definitely works)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
public class WorkerPoolExample
{
private class TaskArguments
{
public int A { get; set; }
public int B { get; set; }
}
private Thread[] _pool;
private object _queueLocker = new object();
private AutoResetEvent _newWorkEvent = new AutoResetEvent(false);
private Queue<TaskArguments> _workQueue = new Queue<TaskArguments>();
private bool _runFlag = true;
public event EventHandler TaskComplete;
public WorkerPoolExample(int threadCount)
{
_pool = new Thread[threadCount];
for (int i = 0; i < _pool.Length; i++)
{
_pool[i] = new Thread((ThreadStart)ConsumerTask);
_pool[i].Start();
}
Application.ApplicationExit += delegate
{
_runFlag = false;
_newWorkEvent.Set();
};
}
public void AddTask(int a, int b)
{
AddTask(new TaskArguments() { A = a, B = b });
}
public void AddTask(TaskArguments args)
{
lock (_queueLocker)
{
_workQueue.Enqueue(args);
}
_newWorkEvent.Set();
}
public void AddTaskRange(TaskArguments[] args)
{
lock (_queueLocker)
{
foreach (var task in args)
_workQueue.Enqueue(task);
}
_newWorkEvent.Set();
}
private void ConsumerTask()
{
while (_runFlag)
{
_newWorkEvent.WaitOne();
if (_workQueue.Count > 0)
{
TaskArguments args = null;
lock (_queueLocker)
{
args = _workQueue.Dequeue();
}
if (args != null)
{
DoWorkMethod(args);
if (TaskComplete != null)
TaskComplete(args, new EventArgs());
}
}
}
}
private void DoWorkMethod(TaskArguments args)
{
Console.WriteLine(args.A + args.B);
Thread.Sleep(100);
}
}