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 `RegisteredWaitHandle`s when and only when its wait is completed?