Reputation: 383
I'm writing a C# program which involves multithreading and synchronization between multiple threads. The threads all need perform some iterative work independently, and after some thread has finished a specified number of iterations, it must wait for the other threads to come up. After all of them have finished given number of iterations and obtained some intermediate result, they should do some synchronized work and then continue execution again, until another synchronization point is reached and so on.
Here's my attempt to achieve this (a thread should pause after just one iteration, then wait for the others):
int nThreads = Environment.ProcessorCount;
Thread[] threads = new Thread[nThreads];
ManualResetEvent[] manualResetEvents = new ManualResetEvent[nThreads];
for (int i = 0; i < nThreads; i++)
{
manualResetEvents[i] = new ManualResetEvent(false);
}
int nSteps = 5;
Random rnd = new Random();
for (int i = 0; i < nThreads; i++)
{
int idx = i;
threads[i] = new Thread(delegate ()
{
int cStep = nSteps;
while (cStep > 0)
{
manualResetEvents[idx].Reset();
Console.Write("\nThread {0} working... cStep = {1}\n", idx, cStep);
Thread.Sleep(rnd.Next(1000));
manualResetEvents[idx].Set();
Console.WriteLine("\nThread {0} work done. Waiting Others...cStep = {1}\n", idx, cStep);
WaitHandle.WaitAll(manualResetEvents);
cStep--;
}
});
}
for (int i = 0; i < nThreads; i++)
{
threads[i].Start();
}
for (int i = 0; i < nThreads; i++)
{
threads[i].Join();
}
But the code above appears not working, for not any thread waits for all of the other threads to perform one iteration for some reason. I think I misunderstand the purpose of ManualResetEvent or use it the wrong way, what could you suggest?
Upvotes: 2
Views: 1453
Reputation: 41474
Your code is prone to race conditions. After all threads have completed the first iteration, all events are still set; if a single thread then runs through the loop before the others get to reset their events, it'll see the other events still set, and stop waiting early.
There's plenty of ways to resolve this bug, but the best solution for you is System.Threading.Barrier
(also see Threading objects and features with section about Barrier). It's explicitly designed for this situation, where you want multiple threads to work in parallel through a multi-step algorithm.
Upvotes: 2