Showing the changes to Source/Libraries/GSF.Core/Threading/InterprocessReaderWriterLock.cs (1 of 14 files). Show all
Unified · Split
| @@ -29,7 +29,7 @@ using System.Threading; · 28 unmodified lines | |||
| 29 | namespace GSF.Threading | 29 | namespace GSF.Threading |
| 30 | { | 30 | { |
| 31 | /// <summary> | 31 | /// <summary> |
| 32 | /// Represents an interprocess reader/writer lock using <see cref="Semaphore"/> and <see cref="Mutex"/> native locking mechanisms. | 32 | /// Represents an inter-process reader/writer lock using <see cref="Semaphore"/> and <see cref="Mutex"/> native locking mechanisms. |
| 33 | /// </summary> | 33 | /// </summary> |
| 34 | public class InterprocessReaderWriterLock : IDisposable | 34 | public class InterprocessReaderWriterLock : IDisposable |
| 35 | { | 35 | { |
| @@ -43,9 +43,9 @@ namespace GSF.Threading · 7 unmodified lines | |||
| 43 | public const int DefaultMaximumConcurrentLocks = 10; | 43 | public const int DefaultMaximumConcurrentLocks = 10; |
| 44 | 44 | ||
| 45 | // Fields | 45 | // Fields |
| 46 | private Mutex m_semaphoreLock; // Mutex used to synchronize access to Semaphore | 46 | private Mutex m_semaphoreLock; // Mutex used to synchronize access to Semaphore |
| 47 | private Semaphore m_concurrencyLock; // Semaphore used for reader/writer lock on consumer object | 47 | private Semaphore m_concurrencyLock; // Semaphore used for reader/writer lock on consumer object |
| 48 | private readonly int m_maximumConcurrentLocks; | 48 | private readonly int m_maximumConcurrentLocks; // Maximum number of concurrent locks before waiting |
| 49 | private bool m_disposed; | 49 | private bool m_disposed; |
| 50 | 50 | ||
| 51 | #endregion | 51 | #endregion |
| @@ -56,7 +56,7 @@ namespace GSF.Threading · 4 unmodified lines | |||
| 56 | /// Creates a new instance of the <see cref="InterprocessReaderWriterLock"/> associated with the specified | 56 | /// Creates a new instance of the <see cref="InterprocessReaderWriterLock"/> associated with the specified |
| 57 | /// <paramref name="name"/> that identifies a source object needing concurrency locking. | 57 | /// <paramref name="name"/> that identifies a source object needing concurrency locking. |
| 58 | /// </summary> | 58 | /// </summary> |
| 59 | /// <param name="name">Identifiying name of source object needing concurrency locking (e.g., a path and file name).</param> | 59 | /// <param name="name">Identifying name of source object needing concurrency locking (e.g., a path and file name).</param> |
| 60 | public InterprocessReaderWriterLock(string name) | 60 | public InterprocessReaderWriterLock(string name) |
| 61 | : this(name, DefaultMaximumConcurrentLocks) | 61 | : this(name, DefaultMaximumConcurrentLocks) |
| 62 | { | 62 | { |
| @@ -66,7 +66,7 @@ namespace GSF.Threading · 3 unmodified lines | |||
| 66 | /// Creates a new instance of the <see cref="InterprocessReaderWriterLock"/> associated with the specified | 66 | /// Creates a new instance of the <see cref="InterprocessReaderWriterLock"/> associated with the specified |
| 67 | /// <paramref name="name"/> that identifies a source object needing concurrency locking. | 67 | /// <paramref name="name"/> that identifies a source object needing concurrency locking. |
| 68 | /// </summary> | 68 | /// </summary> |
| 69 | /// <param name="name">Identifiying name of source object needing concurrency locking (e.g., a path and file name).</param> | 69 | /// <param name="name">Identifying name of source object needing concurrency locking (e.g., a path and file name).</param> |
| 70 | /// <param name="maximumConcurrentLocks">Maximum concurrent reader locks to allow.</param> | 70 | /// <param name="maximumConcurrentLocks">Maximum concurrent reader locks to allow.</param> |
| 71 | /// <remarks> | 71 | /// <remarks> |
| 72 | /// If more reader locks are requested than the <paramref name="maximumConcurrentLocks"/>, excess reader locks will simply | 72 | /// If more reader locks are requested than the <paramref name="maximumConcurrentLocks"/>, excess reader locks will simply |
| @@ -128,12 +128,16 @@ namespace GSF.Threading · 55 unmodified lines | |||
| 128 | if (disposing) | 128 | if (disposing) |
| 129 | { | 129 | { |
| 130 | if ((object)m_concurrencyLock != null) | 130 | if ((object)m_concurrencyLock != null) |
| 131 | { | ||
| 131 | m_concurrencyLock.Close(); | 132 | m_concurrencyLock.Close(); |
| 132 | m_concurrencyLock = null; | 133 | m_concurrencyLock = null; |
| 134 | } | ||
| 133 | 135 | ||
| 134 | if ((object)m_semaphoreLock != null) | 136 | if ((object)m_semaphoreLock != null) |
| 137 | { | ||
| 135 | m_semaphoreLock.Close(); | 138 | m_semaphoreLock.Close(); |
| 136 | m_semaphoreLock = null; | 139 | m_semaphoreLock = null; |
| 140 | } | ||
| 137 | } | 141 | } |
| 138 | } | 142 | } |
| 139 | finally | 143 | finally |
| @@ -147,7 +151,7 @@ namespace GSF.Threading · 7 unmodified lines | |||
| 147 | /// Tries to enter the lock in read mode. | 151 | /// Tries to enter the lock in read mode. |
| 148 | /// </summary> | 152 | /// </summary> |
| 149 | /// <remarks> | 153 | /// <remarks> |
| 150 | /// Upon successful aquistion of a read lock, use the <c>finally</c> block of a <c>try/finally</c> statement to call <see cref="ExitReadLock"/>. | 154 | /// Upon successful acquisition of a read lock, use the <c>finally</c> block of a <c>try/finally</c> statement to call <see cref="ExitReadLock"/>. |
| 151 | /// One <see cref="ExitReadLock"/> should be called for each <see cref="EnterReadLock"/> or <see cref="TryEnterReadLock"/>. | 155 | /// One <see cref="ExitReadLock"/> should be called for each <see cref="EnterReadLock"/> or <see cref="TryEnterReadLock"/>. |
| 152 | /// </remarks> | 156 | /// </remarks> |
| 153 | public void EnterReadLock() | 157 | public void EnterReadLock() |
| @@ -159,7 +163,7 @@ namespace GSF.Threading · 5 unmodified lines | |||
| 159 | /// Tries to enter the lock in write mode. | 163 | /// Tries to enter the lock in write mode. |
| 160 | /// </summary> | 164 | /// </summary> |
| 161 | /// <remarks> | 165 | /// <remarks> |
| 162 | /// Upon successful aquistion of a write lock, use the <c>finally</c> block of a <c>try/finally</c> statement to call <see cref="ExitWriteLock"/>. | 166 | /// Upon successful acquisition of a write lock, use the <c>finally</c> block of a <c>try/finally</c> statement to call <see cref="ExitWriteLock"/>. |
| 163 | /// One <see cref="ExitWriteLock"/> should be called for each <see cref="EnterWriteLock"/> or <see cref="TryEnterWriteLock"/>. | 167 | /// One <see cref="ExitWriteLock"/> should be called for each <see cref="EnterWriteLock"/> or <see cref="TryEnterWriteLock"/>. |
| 164 | /// </remarks> | 168 | /// </remarks> |
| 165 | public void EnterWriteLock() | 169 | public void EnterWriteLock() |
| @@ -171,7 +175,7 @@ namespace GSF.Threading · 5 unmodified lines | |||
| 171 | /// Exits read mode and returns the prior read lock count. | 175 | /// Exits read mode and returns the prior read lock count. |
| 172 | /// </summary> | 176 | /// </summary> |
| 173 | /// <remarks> | 177 | /// <remarks> |
| 174 | /// Upon successful aquistion of a read lock, use the <c>finally</c> block of a <c>try/finally</c> statement to call <see cref="ExitReadLock"/>. | 178 | /// Upon successful acquisition of a read lock, use the <c>finally</c> block of a <c>try/finally</c> statement to call <see cref="ExitReadLock"/>. |
| 175 | /// One <see cref="ExitReadLock"/> should be called for each <see cref="EnterReadLock"/> or <see cref="TryEnterReadLock"/>. | 179 | /// One <see cref="ExitReadLock"/> should be called for each <see cref="EnterReadLock"/> or <see cref="TryEnterReadLock"/>. |
| 176 | /// </remarks> | 180 | /// </remarks> |
| 177 | public int ExitReadLock() | 181 | public int ExitReadLock() |
| @@ -184,7 +188,7 @@ namespace GSF.Threading · 6 unmodified lines | |||
| 184 | /// Exits write mode. | 188 | /// Exits write mode. |
| 185 | /// </summary> | 189 | /// </summary> |
| 186 | /// <remarks> | 190 | /// <remarks> |
| 187 | /// Upon successful aquistion of a write lock, use the <c>finally</c> block of a <c>try/finally</c> statement to call <see cref="ExitWriteLock"/>. | 191 | /// Upon successful acquisition of a write lock, use the <c>finally</c> block of a <c>try/finally</c> statement to call <see cref="ExitWriteLock"/>. |
| 188 | /// One <see cref="ExitWriteLock"/> should be called for each <see cref="EnterWriteLock"/> or <see cref="TryEnterWriteLock"/>. | 192 | /// One <see cref="ExitWriteLock"/> should be called for each <see cref="EnterWriteLock"/> or <see cref="TryEnterWriteLock"/>. |
| 189 | /// </remarks> | 193 | /// </remarks> |
| 190 | public void ExitWriteLock() | 194 | public void ExitWriteLock() |
| @@ -199,12 +203,12 @@ namespace GSF.Threading · 8 unmodified lines | |||
| 199 | /// <param name="millisecondsTimeout">The number of milliseconds to wait, or -1 (<see cref="Timeout.Infinite"/>) to wait indefinitely.</param> | 203 | /// <param name="millisecondsTimeout">The number of milliseconds to wait, or -1 (<see cref="Timeout.Infinite"/>) to wait indefinitely.</param> |
| 200 | /// <returns><c>true</c> if the calling thread entered read mode, otherwise, <c>false</c>.</returns> | 204 | /// <returns><c>true</c> if the calling thread entered read mode, otherwise, <c>false</c>.</returns> |
| 201 | /// <remarks> | 205 | /// <remarks> |
| 202 | /// Upon successful aquistion of a read lock, use the <c>finally</c> block of a <c>try/finally</c> statement to call <see cref="ExitReadLock"/>. | 206 | /// Upon successful acquisition of a read lock, use the <c>finally</c> block of a <c>try/finally</c> statement to call <see cref="ExitReadLock"/>. |
| 203 | /// One <see cref="ExitReadLock"/> should be called for each <see cref="EnterReadLock"/> or <see cref="TryEnterReadLock"/>. | 207 | /// One <see cref="ExitReadLock"/> should be called for each <see cref="EnterReadLock"/> or <see cref="TryEnterReadLock"/>. |
| 204 | /// </remarks> | 208 | /// </remarks> |
| 205 | public bool TryEnterReadLock(int millisecondsTimeout) | 209 | public bool TryEnterReadLock(int millisecondsTimeout) |
| 206 | { | 210 | { |
| 207 | bool success = false; | 211 | bool success; |
| 208 | 212 | ||
| 209 | try | 213 | try |
| 210 | { | 214 | { |
| @@ -263,7 +267,9 @@ namespace GSF.Threading · 52 unmodified lines | |||
| 263 | // The only way to get a semaphore slot count is to execute a successful wait and release. | 267 | // The only way to get a semaphore slot count is to execute a successful wait and release. |
| 264 | startTime = DateTime.UtcNow.Ticks; | 268 | startTime = DateTime.UtcNow.Ticks; |
| 265 | 269 | ||
| 266 | if (success = m_concurrencyLock.WaitOne(millisecondsTimeout)) | 270 | success = m_concurrencyLock.WaitOne(millisecondsTimeout); |
| 271 | |||
| 272 | if (success) | ||
| 267 | { | 273 | { |
| 268 | int count = m_concurrencyLock.Release(); | 274 | int count = m_concurrencyLock.Release(); |
| 269 | int adjustedTimeout = millisecondsTimeout; | 275 | int adjustedTimeout = millisecondsTimeout; |
| @@ -282,7 +288,9 @@ namespace GSF.Threading · 12 unmodified lines | |||
| 282 | if (adjustedTimeout < 0) | 288 | if (adjustedTimeout < 0) |
| 283 | adjustedTimeout = 0; | 289 | adjustedTimeout = 0; |
| 284 | 290 | ||
| 285 | if (success = m_concurrencyLock.WaitOne(adjustedTimeout)) | 291 | success = m_concurrencyLock.WaitOne(adjustedTimeout); |
| 292 | |||
| 293 | if (success) | ||
| 286 | count = m_concurrencyLock.Release(); | 294 | count = m_concurrencyLock.Release(); |
| 287 | } | 295 | } |
| 288 | } | 296 | } |