116 lines
3.3 KiB
C#
Raw Normal View History

// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
#if SILVERLIGHT
using System;
namespace System.Threading
{
//Monitor based implementation of Semaphore
//that mimicks the .NET Semaphore class (System.Threading.Semaphore)
internal sealed class Semaphore : IDisposable
{
private int m_currentCount;
private int m_maximumCount;
private object m_lockObject;
private bool m_disposed;
public Semaphore(int initialCount, int maximumCount)
{
if (initialCount < 0)
{
throw new ArgumentOutOfRangeException("initialCount", "Non-negative number required.");
}
if (maximumCount < 1)
{
throw new ArgumentOutOfRangeException("maximumCount", "Positive number required.");
}
if (initialCount > maximumCount)
{
throw new ArgumentException("Initial count must be smaller than maximum");
}
m_currentCount = initialCount;
m_maximumCount = maximumCount;
m_lockObject = new object();
}
public int Release()
{
return this.Release(1);
}
public int Release(int releaseCount)
{
if (releaseCount < 1)
{
throw new ArgumentOutOfRangeException("releaseCount", "Positive number required.");
}
if (m_disposed)
{
throw new ObjectDisposedException("Semaphore");
}
var oldCount = default(int);
lock (m_lockObject)
{
oldCount = m_currentCount;
if (releaseCount + m_currentCount > m_maximumCount)
{
throw new ArgumentOutOfRangeException("releaseCount", "Amount of releases would overflow maximum");
}
m_currentCount += releaseCount;
//PulseAll makes sure all waiting threads get queued for acquiring the lock
//Pulse would only queue one thread.
Monitor.PulseAll(m_lockObject);
}
return oldCount;
}
public bool WaitOne()
{
return WaitOne(Timeout.Infinite);
}
public bool WaitOne(int millisecondsTimeout)
{
if (m_disposed)
{
throw new ObjectDisposedException("Semaphore");
}
lock (m_lockObject)
{
while (m_currentCount == 0)
{
if (!Monitor.Wait(m_lockObject, millisecondsTimeout))
{
return false;
}
}
m_currentCount--;
return true;
}
}
public bool WaitOne(TimeSpan timeout)
{
return WaitOne((int)timeout.TotalMilliseconds);
}
public void Close()
{
Dispose();
}
public void Dispose()
{
//the .NET CLR semaphore does not release waits upon dispose
//so we don't do that either.
m_disposed = true;
m_lockObject = null;
}
}
}
#endif