/// <summary>P the semaphore (take out 1 unit from it).</summary> public void P() { // Lock so we can work in peace. This works because lock is actually // built around Monitor. using (TimedLock.Lock(this)) { // Wait until a unit becomes available. We need to wait // in a loop in case someone else wakes up before us. This could // happen if the Monitor.Pulse statements were changed to Monitor.PulseAll // statements in order to introduce some randomness into the order // in which threads are woken. while (_count <= 0) { Monitor.Wait(this, Timeout.Infinite); } _count--; } }
/// <summary>A thread worker function that processes items from the work queue.</summary> private static void ProcessQueuedItems() { // Process indefinitely while (true) { // Get the next item in the queue. If there is nothing there, go to sleep // for a while until we're woken up when a callback is waiting. WaitingCallback callback = null; while (callback == null) { // Try to get the next callback available. We need to lock on the // queue in order to make our count check and retrieval atomic. using (TimedLock.Lock(_waitingCallbacks.SyncRoot)) { if (_waitingCallbacks.Count > 0) { try { callback = (WaitingCallback)_waitingCallbacks.Dequeue(); } catch { } // make sure not to fail here } } // If we can't get one, go to sleep. if (callback == null) { _workerThreadNeeded.WaitOne(); } } // We now have a callback. Execute it. Make sure to accurately // record how many callbacks are currently executing. try { Interlocked.Increment(ref _inUseThreads); callback.Callback(callback.State); } catch (Exception) { } finally { Interlocked.Decrement(ref _inUseThreads); } } }
/// <summary>Resets the semaphore to the specified count. Should be used cautiously.</summary> public void Reset(int count) { using (TimedLock.Lock(this)) { _count = count; } }