just want some advice on \"best practice\" regarding multi-threading tasks.
as an example, we have a C# application that upon startup reads data from various \"type
If you are using .NET 3.5 or below, you can use an array of AsyncResult or BackgroundWorker and count how many threads have returned (just don't forget to decrease counter with interlocked operations) (see http://www.albahari.com/threading/ as a reference).
If you are using .NET 4.0 a parallel for is the simplest approach.
Posting to maybe help some others, spent quite a bit of time looking for a solution like what I came up with. So I took a little different approach. I was spinning off numerous threads and incremented a counter and decremented a counter as a thread started and stopped. Then in the main method I was wanting to pause and wait for threads to complete I did.
while (threadCounter > 0)
{
Thread.Sleep(500); //Make it pause for half second so that we don’t spin the cpu out of control.
}
Documented on my blog. http://www.adamthings.com/post/2012/07/11/ensure-threads-have-finished-before-method-continues-in-c/
Assuming the database reader threads return as soon as they're done, you can simply call Thread.Join on all ten threads in turn from the initiating thread.
If you're feeling adventurous you can use C# 4.0 and the Task Parallel Library:
Parallel.ForEach(jobList, curJob => {
curJob.Process()
});
Just for fun, what @Reed has done, with Monitor. :P
class Program
{
static void Main(string[] args)
{
int numThreads = 10;
int toProcess = numThreads;
object syncRoot = new object();
// Start workers.
for (int i = 0; i < numThreads; i++)
{
new Thread(delegate()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
// If we're the last thread, signal
if (Interlocked.Decrement(ref toProcess) == 0)
{
lock (syncRoot)
{
Monitor.Pulse(syncRoot);
}
}
}).Start();
}
// Wait for workers.
lock (syncRoot)
{
if (toProcess > 0)
{
Monitor.Wait(syncRoot);
}
}
Console.WriteLine("Finished.");
}
}
My preference for this is to handle this via a single WaitHandle, and use Interlocked to avoid locking on a counter:
class Program
{
static void Main(string[] args)
{
int numThreads = 10;
ManualResetEvent resetEvent = new ManualResetEvent(false);
int toProcess = numThreads;
// Start workers.
for (int i = 0; i < numThreads; i++)
{
new Thread(delegate()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
// If we're the last thread, signal
if (Interlocked.Decrement(ref toProcess) == 0)
resetEvent.Set();
}).Start();
}
// Wait for workers.
resetEvent.WaitOne();
Console.WriteLine("Finished.");
}
}
This works well, and scales to any number of threads processing, without introducing locking.