Q:

How can I make a thread wait until another thread is wating (C#)

I have a consumer thread that creates some worker threads.  These threads must switch between active and waiting states.  When all worker threads are in the waiting states, it means that the current job is done.  How can I make the consumer thread wait for all the worker threads to be in the waiting state?  I want a behavior very similar to Thread. Join() on all worker threads, however, I want the threads to keep running for the next job.  I cannot create new threads because the jobs are in a tight loop and creating new threads is costly. 

A:

As far as I am aware there is no mechanism to do what you wish. ( Thread. Join but since you can't block that is not an option)
From the info you provided it sounds like your really building a state machine, just across multiple threads. 
I would create a Singleton and have that act as a state machine.  Threads could signal to the Singleton there status.  
It sounds like you have an indeterminate number of threads, so you would need to put the status of each in a collection.  I would look here Thread Safe Collections to find the right fit for how you wish to store your state information. 
Hope this helps. 

A:

Apologies for the brief answer (may expand later), but you probably the WaitHandle. WaitAll method, combined with a ManualResetEvent.  You would pass your ManualResetEvent objects into each worker thread when they're created, signal them when they become idle, and pass the entire set of handles into the WaitHandle. WaitAll method to wake the observing thread when they're complete.  You can also use the timeout feature of this method if you want to periodically run some kind of task while waiting, or perform some kind of operation if the task is taking too long. 
Note that if your worker threads are intended to terminate when the operation is complete (wasn't totally clear if this is the case), it might be more appropriate to spawn them as tasks and use Task. WaitAll instead. 
Edit: On a quick re-read, it sounds like you do want to be using tasks rather than trying to re-use full worker threads.  Tasks use threads which have been allocated from the thread pool, eliminating that thread creation overhead you were worried about, because the threads will (generally) be ready and waiting for work.  You can simply spawn each task and wait for them all to be finished.