JD2022-TU1/main/tools/framework/JD.Threading/PVSemaphore.cs

106 lines
3.1 KiB
C#

using System;
using System.Threading;
namespace JD.Threading
{
/// <summary>
/// Implementation of Dijkstra's PV Semaphore based on the Monitor class.
/// See http://en.wikipedia.org/wiki/Semaphore_(programming)
/// </summary>
public sealed class PVSemaphore
{
#region Variables
/// <summary>
/// The number of units alloted by this semaphore.
/// </summary>
private int m_count;
/// <summary>
/// Lock for the semaphore.
/// </summary>
private readonly object m_semaphoreLock = new object();
#endregion
#region Constructors
/// <summary>
/// Initialize the semaphore as a binary semaphore.
/// </summary>
public PVSemaphore()
: this(1)
{
}
/// <summary>
/// Initialize the semaphore as a counting semaphore.
/// </summary>
/// <param name="count">Initial number of threads that can take out units from this semaphore.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if the count argument is less than 0.</exception>
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
/// <summary>
/// V the semaphore (add 1 unit to it).
/// </summary>
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);
}
}
/// <summary>
/// P the semaphore (wait and take out 1 unit from it).
/// </summary>
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--;
}
}
/// <summary>
/// Resets the semaphore to the specified count. Should be used cautiously.
/// </summary>
public void Reset(int count)
{
lock (m_semaphoreLock)
{
m_count = count;
}
}
#endregion
}
}