using System; using System.Threading; namespace JD.Threading { /// /// Implementation of Dijkstra's PV Semaphore based on the Monitor class. /// See http://en.wikipedia.org/wiki/Semaphore_(programming) /// public sealed class PVSemaphore { #region Variables /// /// The number of units alloted by this semaphore. /// private int m_count; /// /// Lock for the semaphore. /// private readonly object m_semaphoreLock = new object(); #endregion #region Constructors /// /// Initialize the semaphore as a binary semaphore. /// public PVSemaphore() : this(1) { } /// /// Initialize the semaphore as a counting semaphore. /// /// Initial number of threads that can take out units from this semaphore. /// Thrown if the count argument is less than 0. public PVSemaphore(int count) { if (count < 0) { throw new ArgumentOutOfRangeException("count", count, "Semaphore must have a count of at least 0."); } m_count = count; } #endregion #region Methods /// /// V the semaphore (add 1 unit to it). /// public void AddOne() { // Lock so we can work in peace. This works because lock is actually // built around Monitor. lock (m_semaphoreLock) { // Release our hold on the unit of control. Then tell everyone // waiting on this object that there is a unit available. m_count++; Monitor.Pulse(m_semaphoreLock); } } /// /// P the semaphore (wait and take out 1 unit from it). /// public void WaitOne() { // Lock so we can work in peace. This works because lock is actually // built around Monitor. lock (m_semaphoreLock) { // 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 (m_count <= 0) { Monitor.Wait(m_semaphoreLock, Timeout.Infinite); } m_count--; } } /// /// Resets the semaphore to the specified count. Should be used cautiously. /// public void Reset(int count) { lock (m_semaphoreLock) { m_count = count; } } #endregion } }