I would not use RegisterWaitForSingleObject for this purpose. The samples I'm going to describe here require downloading Reactive Extensions since you are using .NET v3.5.
First, to wait for the use of all work items from ThreadPool to use the CountdownEvent class. This is much more elegant and scalable than using multiple instances of ManualResetEvent . In addition, the WaitHandle.WaitAll method WaitHandle.WaitAll limited to 64 handles.
var finished = new CountdownEvent(1); for (int i = 0; i < table_seats; i++) { finished.AddCount(); ThreadPool.QueueUserWorkItem(ObserveSeat); (state) => { try { ObserveSeat(state); } finally { finished.Signal(); } }, i); } finished.Signal(); finished.Wait();
Secondly, you can try calling Thread.Sleep(0) after several iterations of the loop to force the context switch so that the current thread gives another. If you want a much more complex coordination strategy, use the Barrier class. Add another parameter to your ObserveSeat function, which accepts this synchronization mechanism. You can provide it by capturing it in a lambda expression in the code above.
public void ObserveSeat(object state, Barrier barrier) { barrier.AddParticipant(); try { for (int i = 0; i < NUM_ITERATIONS; i++) { if (i % AMOUNT == 0) {
Note that while this approach will undoubtedly prevent the problem of starvation, it can limit the bandwidth of the threads. Calling SignalAndWait too much can cause a lot of unnecessary context switching, but calling it too little can cause a lot of unnecessary waiting. You will probably need to tune AMOUNT to get the optimal balance of bandwidth and hunger. I suspect there might be an easy way to do the setup dynamically.
Brian gideon
source share