1 // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. 2 3 #if SILVERLIGHT 4 using System; 5 6 namespace System.Threading 7 { 8 //Monitor based implementation of Semaphore 9 //that mimicks the .NET Semaphore class (System.Threading.Semaphore) 10 11 internal sealed class Semaphore : IDisposable 12 { 13 private int m_currentCount; 14 private int m_maximumCount; 15 private object m_lockObject; 16 private bool m_disposed; 17 Semaphore(int initialCount, int maximumCount)18 public Semaphore(int initialCount, int maximumCount) 19 { 20 if (initialCount < 0) 21 { 22 throw new ArgumentOutOfRangeException("initialCount", "Non-negative number required."); 23 } 24 if (maximumCount < 1) 25 { 26 throw new ArgumentOutOfRangeException("maximumCount", "Positive number required."); 27 } 28 if (initialCount > maximumCount) 29 { 30 throw new ArgumentException("Initial count must be smaller than maximum"); 31 } 32 33 m_currentCount = initialCount; 34 m_maximumCount = maximumCount; 35 m_lockObject = new object(); 36 } 37 Release()38 public int Release() 39 { 40 return this.Release(1); 41 } 42 Release(int releaseCount)43 public int Release(int releaseCount) 44 { 45 if (releaseCount < 1) 46 { 47 throw new ArgumentOutOfRangeException("releaseCount", "Positive number required."); 48 } 49 if (m_disposed) 50 { 51 throw new ObjectDisposedException("Semaphore"); 52 } 53 54 var oldCount = default(int); 55 lock (m_lockObject) 56 { 57 oldCount = m_currentCount; 58 if (releaseCount + m_currentCount > m_maximumCount) 59 { 60 throw new ArgumentOutOfRangeException("releaseCount", "Amount of releases would overflow maximum"); 61 } 62 m_currentCount += releaseCount; 63 //PulseAll makes sure all waiting threads get queued for acquiring the lock 64 //Pulse would only queue one thread. 65 66 Monitor.PulseAll(m_lockObject); 67 } 68 return oldCount; 69 } 70 WaitOne()71 public bool WaitOne() 72 { 73 return WaitOne(Timeout.Infinite); 74 } 75 WaitOne(int millisecondsTimeout)76 public bool WaitOne(int millisecondsTimeout) 77 { 78 if (m_disposed) 79 { 80 throw new ObjectDisposedException("Semaphore"); 81 } 82 83 lock (m_lockObject) 84 { 85 while (m_currentCount == 0) 86 { 87 if (!Monitor.Wait(m_lockObject, millisecondsTimeout)) 88 { 89 return false; 90 } 91 } 92 m_currentCount--; 93 return true; 94 } 95 } 96 WaitOne(TimeSpan timeout)97 public bool WaitOne(TimeSpan timeout) 98 { 99 return WaitOne((int)timeout.TotalMilliseconds); 100 } 101 Close()102 public void Close() 103 { 104 Dispose(); 105 } 106 Dispose()107 public void Dispose() 108 { 109 //the .NET CLR semaphore does not release waits upon dispose 110 //so we don't do that either. 111 m_disposed = true; 112 m_lockObject = null; 113 } 114 } 115 } 116 #endif