How to stop one thread until n threads have completed their work

I have an application with one main thread and N workflows. At some point, I need the main thread to wait until all the N threads have completed one part of their work.

I usually use Monitor.Wait () and Monitor.Pulse (), but this will prevent N threads from working at the same time.

Any idea on how to do this?

Thanks in advance.

+4
source share
10 answers

Good thing I'm doing now (using your ideas) and it seems to work:

I announced a ManualResetEvent list:

Private m_waitHandles As List(Of Threading.ManualResetEvent) 

The process accepts incoming Tcp connections and starts one thread for each connection. Therefore, in the new client handler, I added this code:

 Dim waitHandle As Threading.ManualResetEvent waitHandle = New Threading.ManualResetEvent(True) SyncLock (DirectCast(m_waitHandles, IList).SyncRoot) m_waitHandles.Add(waitHandle) End SyncLock ''# Do all the work StoppableMethod() SyncLock (DirectCast(m_waitHandles, IList).SyncRoot) waitHandle = m_waitHandles.Item(Threading.WaitHandle.WaitAny(m_waitHandles.ToArray())) End SyncLock waitHandle.Reset() NonStoppableMethod() waitHandle.Set() SyncLock (DirectCast(m_waitHandles, IList).SyncRoot) m_waitHandles.Remove(waitHandle) End SyncLock 

The last thing to do is change the Stop method to make sure that the Stop operation will not be executed on any thread inside NonStoppableMethod:

 SyncLock (DirectCast(m_waitHandles, IList).SyncRoot) If m_waitHandles.Count > 0 Then Threading.WaitHandle.WaitAll(m_waitHandles.ToArray()) End If End SyncLock 

I’m not sure that this is done correctly, because for the first time I do such things. Do you feel that this is normal and is a good approach?

Thanks to everyone, comrades!

+1
source

.NET 4.0 will include the System.Threading.Barrier class, which will simplify synchronization between multiple threads. A blog post with good example code can be found here .

Similar functionality can be achieved using several WaitHandles in .NET 3.0+, as shown in this example on MSDN.

A quick tour of the MSDN example:

 const int numberOfWorkers = 5; static void Main() { var handles = new ManualResetEvent[numberOfWorkers]; for (int i = 0; i < numberOfWorkers; i++) { handles[i] = new ManualResetEvent(false); ThreadPool.QueueUserWorkItem(o => worker.Work(), null); } // Wait for all workers to finish before continuing WaitHandle.WaitAll(handles); /* continue execution... */ } 
+8
source

Do something like garbage collection. You will write a ThreadManager that indicates the number of threads. When the main thread starts a new worker, ThreadManager will increase the number of workers. When the worker finishes work, he will inform ThreadManager, which will reduce the number of threads. When it has zero worker threads, the ThreadManager will wake up the main thread.

+2
source

It seems that WaitHandle.WaitAll should solve this problem.

In your main thread, you will need to maintain links to workflow wait descriptors. When necessary for synchronization, pass these descriptors to the above method. Workflows signal at the corresponding point in their code.

If the worker threads loop or need to "pulsate" several times, you can use AutoResetEvents , for example:

 public void WorkerMethod() { DoFirstThing(); this.autoResetEvent.Set(); DoSecondThing(); this.autoResetEvent.Set(); // etc. } 

If not (if the main thread just needed to know the worker thread has passed a threshold), ManualResetEvents will be fine.

There are several things to watch out for when using WaitAll (from MSDN WaitAll documentation):

In some implementations, if more than 64 handles pass, the NotSupportedException exception is fixed. If the array contains duplicates, the call failed with a DuplicateWaitObjectException.

However, it is rare that a process can actually use more than 64 threads, so this limitation often does not matter.

+2
source

He called the barrier: http://programmingexamples.wikidot.com/java-barrier

Ow, but if you only need the first thread to wait for the rest to pass some point, and you want the other to continue to work, use a semaphore of size N and let all the other threads take it, and this first thread will wait, to purchase it after them.

Semaphore: http://programmingexamples.wikidot.com/java-semaphore

+1
source

If you just need to wait until threads stop, how about Thread.Join ? In .NET 4.0, you can use Task.WaitAll . If you need to wait until they finish only part of their task, this is a little deceiving. In current versions of .NET, see WaitHandle.WaitAll / Threading.ManualResetEvent . In .NET 4.0 you can use Threading.Barrier .

+1
source

Since on some implementations there is a limit on the number of descriptors WaitHandle.WaitAll() ... handle, (see msdn-WaitHandle.WaitAll () , I created a utility method for this:

  public static void WaitAll(WaitHandle[] handles) { if (handles == null) throw new ArgumentNullException("handles", "WaitHandle[] handles was null"); foreach (WaitHandle wh in handles) wh.WaitOne(); } 

the use is to add a wait descriptor for each thread to the array, and then call the aforementioned utility method (pass the array) after all threads have been initiated.

  List<WaitHandle> waitHndls = new List<WaitHandle>(); foreach (MyType mTyp in MyTypeCollection) { ManualResetEvent txEvnt = new ManualResetEvent(false); int qryNo1 = ++qryNo; ThreadPool.QueueUserWorkItem( delegate { try { // Code to execute whatever thread function is... } catch (SomeCustomException iX) { // catch code } } finally { lock (locker) txEvnt.Set(); } }); waitHndls.Add(txEvnt); } util.WaitAll(waitHndls.ToArray()); 
+1
source

Try using this:

 int threadsCompleted = 0; int numberOfThreads = 4; ManualResetEvent completedEvent = new ManualResetEvent(false); 

In each thread:

 // Do task if (Interlocked.Increment(threadsCompleted) == numberOfThreads) completedEvent.Set(); 

Main theme:

 completedEvent.WaitOne(); 
+1
source

All over the world, people are trying to use an array of EventHandles and WaitAll() . I came up with the following class, which is much lighter than resources. I tried to think of different race scenarios, and I believe that there is no race in this code. (There is a theoretical race between decrement and checking the status on Count , but as far as I can tell, this does not affect the functionality, and the code will still work.)

To use this class, all threads requiring synchronization must call its Wait() method. They will be blocked until Count number of threads is called Wait() . One instance can only be used for synchronization once (it cannot be reset).

 internal class ThreadBarrier { private ManualResetEvent BarrierEvent; private int Count; internal ThreadBarrier(int count) { BarrierEvent = new ManualResetEvent(false); Count = count; } internal void Wait() { Interlocked.Decrement(ref Count); if (Count > 0) BarrierEvent.WaitOne(); else BarrierEvent.Set(); } } 
+1
source

Use Thread.Join (which blocks the calling thread until the thread terminates, continuing to execute standard COM and SendMessage), as in the example:

 using System; using System.Threading; class IsThreadPool { static void Main() { AutoResetEvent autoEvent = new AutoResetEvent(false); Thread regularThread = new Thread(new ThreadStart(ThreadMethod)); regularThread.Start(); ThreadPool.QueueUserWorkItem(new WaitCallback(WorkMethod), autoEvent); // __________ Wait for foreground thread to end. __________ regularThread.Join(); // Wait for background thread to end. autoEvent.WaitOne(); } static void ThreadMethod() { Console.WriteLine("ThreadOne, executing ThreadMethod, " + "is {0}from the thread pool.", Thread.CurrentThread.IsThreadPoolThread ? "" : "not "); } static void WorkMethod(object stateInfo) { Console.WriteLine("ThreadTwo, executing WorkMethod, " + "is {0}from the thread pool.", Thread.CurrentThread.IsThreadPoolThread ? "" : "not "); // Signal that this thread is finished. ((AutoResetEvent)stateInfo).Set(); } } 
0
source

All Articles