I’m using ThreadPool.UnsafeRegisterWaitForSingleObject (henceforth RWFSO) to asynchronously wait on a Semaphore. It returns me a RegisteredWaitHandle which I cannot easily Unregister(). I need to unregister these because the handle is keeping a reference to the delegate and its state object and my process is leaking memory with each handle. Eventually they do get finalized, but this takes far too long and puts far too much pressure on the GC, ballooning my process’s private memory usage up into the 1.8GB range. I’m making a lot of asynchronous requests.
The semaphore is used to gate access to HttpWebRequest‘s asynchronous implementation: BeginGetRequestStream and BeginGetResponse. If I don’t use a semaphore, it keeps telling me “not enough free threads on the thread pool” because of the moronic way in which it was implemented. If I use blocking primitives like semaphore.WaitOne() then my thread pool will eventually be deadlocked and nothing will make progress.
RWFSO returns a RegisteredWaitHandle but this is useless to my calling thread as I need to Unregister() this handle only when the wait is completed; I have no cancellation scenario. I can’t just pass the RegisteredWaitHandle instance to my delegate (via an out-of-band field set on the state object passed to the delegate) because the delegate could be completed on another thread before control even returns from RWFSO.
How do I safely and quickly Unregister() a RegisteredWaitHandles when and only when its wait is completed?
Just pass the handle to the delegate via whatever mechanism works for you. If the handle is null by the time the delegate executes, have the delegate spin on waiting for the assignment. Don’t worry about the trivial amount of CPU time used, because you can just put
Thread.Yieldin the loop. If it bothers you, you can use a lock.Alternatively you can unregister the handles that are there, and let the GC clean up the few that lost the race.