I am trying to use ThreadPool.RegisterWaitForSingleObject to add a timer to a set of threads. I create 9 threads and am trying to give each of them an equal chance of operation as at the moment there seems to be a little starvation going on if I just add them to the thread pool. I am also trying to implement a manual reset event as I want all 9 threads to exit before continuing.
What is the best way to ensure that each thread in the threadpool gets an equal chance at running as the function that I am calling has a loop and it seems that each thread (or whichever one runs first) gets stuck in it and the others don’t get a chance to run.
resetEvents = new ManualResetEvent[table_seats];
//Spawn 9 threads
for (int i = 0; i < table_seats; i++)
{
resetEvents[i] = new ManualResetEvent(false);
//AutoResetEvent ev = new AutoResetEvent(false);
RegisteredWaitHandle handle = ThreadPool.RegisterWaitForSingleObject(autoEvent, ObserveSeat, (object)i, 100, false);
}
//wait for threads to exit
WaitHandle.WaitAll(resetEvents);
However, it doesn’t matter if I use resetEvents[] or ev neither seem to work properly. Am I able to implement this or am I (probably) misunderstanding how they should work.
Thanks, R.
I would not use the
RegisterWaitForSingleObjectfor this purpose. The patterns I am going to describe here require the Reactive Extensions download since you are using .NET v3.5.First, to wait for all work items from the
ThreadPoolto complete use theCountdownEventclass. This is a lot more elegant and scalable than using multipleManualResetEventinstances. Plus, theWaitHandle.WaitAllmethod is limited to 64 handles.Second, you could try calling
Thread.Sleep(0)after several iterations of the loop to force a context switch so that the current thread yields to another. If you want a considerably more complex coordination strategy then use theBarrierclass. Add another parameter to yourObserveSeatfunction which accepts this synchronization mechanism. You could supply it by capturing it in the lambda expression in the code above.Note that although this approach would certainly prevent the starvation issue it might limit the throughput of the threads. Calling
SignalAndWaittoo much might cause a lot of unnecessary context switching, but calling it too little might cause a lot of unnecessary waiting. You would probably have to tuneAMOUNTto get the optimal balance of throughput and starvation. I suspect there might be a simple way to do the tuning dynamically.