You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

173 lines
6.4 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. namespace IPA.Utilities
  8. {
  9. /// <summary>
  10. /// Utilities for inter-thread synchronization. All Locker method acquire their object immediately.
  11. /// </summary>
  12. public static class Synchronization
  13. {
  14. #region Public types
  15. /// <summary>
  16. /// A synchronization state locker that releases its state when its <see cref="IDisposable.Dispose"/>
  17. /// method is called. ALWAYS use with a <see langword="using"/> block or statement. Otherwise, the locker
  18. /// may not release the object be released properly.
  19. /// </summary>
  20. public interface ISyncStateLocker : IDisposable { }
  21. /// <summary>
  22. /// A locker type for <see cref="ReaderWriterLockSlim"/> locks.
  23. /// ALWAYS use with a <see langword="using"/> block or statement. Otherwise, the locker
  24. /// may not release the object be released properly.
  25. /// </summary>
  26. public interface IReadWriteLocker : ISyncStateLocker { }
  27. /// <summary>
  28. /// An upgradable locker type for <see cref="ReaderWriterLockSlim"/>.
  29. /// ALWAYS use with a <see langword="using"/> block or statement. Otherwise, the locker
  30. /// may not release the object be released properly.
  31. /// </summary>
  32. public interface IUpgradableLocker : IReadWriteLocker
  33. {
  34. /// <summary>
  35. /// Upgrades the locker and gives a new locker to manage the upgraded lock.
  36. /// </summary>
  37. /// <returns>the locker to use with <see langword="using"/> to manage the write lock</returns>
  38. IReadWriteLocker Upgrade();
  39. }
  40. #endregion
  41. #region Implementations
  42. private sealed class MutexLocker : ISyncStateLocker
  43. {
  44. private readonly Mutex mutex;
  45. public MutexLocker(Mutex mutex)
  46. {
  47. this.mutex = mutex;
  48. mutex.WaitOne(); // wait and acquire mutex
  49. }
  50. public void Dispose() => mutex.ReleaseMutex(); // release mutex
  51. }
  52. private sealed class SemaphoreLocker : ISyncStateLocker
  53. {
  54. private readonly Semaphore sem;
  55. public SemaphoreLocker(Semaphore sem)
  56. {
  57. this.sem = sem;
  58. sem.WaitOne();
  59. }
  60. public void Dispose() => sem.Release();
  61. }
  62. private sealed class SemaphoreSlimLocker : ISyncStateLocker
  63. {
  64. private readonly SemaphoreSlim sem;
  65. public SemaphoreSlimLocker(SemaphoreSlim sem)
  66. {
  67. this.sem = sem;
  68. sem.Wait();
  69. }
  70. public void Dispose() => sem.Release();
  71. }
  72. private sealed class ReaderWriterLockSlimWriteLocker : IReadWriteLocker
  73. {
  74. private readonly ReaderWriterLockSlim rwl;
  75. public ReaderWriterLockSlimWriteLocker(ReaderWriterLockSlim lck)
  76. {
  77. rwl = lck;
  78. rwl.EnterWriteLock();
  79. }
  80. public void Dispose() => rwl.ExitWriteLock();
  81. }
  82. private sealed class ReaderWriterLockSlimReadLocker : IReadWriteLocker
  83. {
  84. private readonly ReaderWriterLockSlim rwl;
  85. public ReaderWriterLockSlimReadLocker(ReaderWriterLockSlim lck)
  86. {
  87. rwl = lck;
  88. rwl.EnterReadLock();
  89. }
  90. public void Dispose() => rwl.ExitReadLock();
  91. }
  92. private sealed class ReaderWriterLockSlimUpgradableReadLocker : IUpgradableLocker
  93. {
  94. private readonly ReaderWriterLockSlim rwl;
  95. public ReaderWriterLockSlimUpgradableReadLocker(ReaderWriterLockSlim lck)
  96. {
  97. rwl = lck;
  98. rwl.EnterUpgradeableReadLock();
  99. }
  100. public IReadWriteLocker Upgrade() => new ReaderWriterLockSlimWriteLocker(rwl);
  101. public void Dispose() => rwl.ExitUpgradeableReadLock();
  102. }
  103. #endregion
  104. #region Accessors
  105. // TODO: add async fun stuff to this
  106. /// <summary>
  107. /// Creates an <see cref="ISyncStateLocker"/> for a mutex.
  108. /// </summary>
  109. /// <param name="mut">the mutex to acquire</param>
  110. /// <returns>the locker to use with <see langword="using"/></returns>
  111. public static ISyncStateLocker Locker(Mutex mut) => new MutexLocker(mut);
  112. /// <summary>
  113. /// Creates an <see cref="ISyncStateLocker"/> for a semaphore.
  114. /// </summary>
  115. /// <param name="sem">the semaphore to acquire</param>
  116. /// <returns>the locker to use with <see langword="using"/></returns>
  117. public static ISyncStateLocker Locker(Semaphore sem) => new SemaphoreLocker(sem);
  118. /// <summary>
  119. /// Creates an <see cref="ISyncStateLocker"/> for a slim semaphore.
  120. /// </summary>
  121. /// <param name="sem">the slim semaphore to acquire</param>
  122. /// <returns>the locker to use with <see langword="using"/></returns>
  123. public static ISyncStateLocker Locker(SemaphoreSlim sem) => new SemaphoreSlimLocker(sem);
  124. /// <summary>
  125. /// Creates an <see cref="IReadWriteLocker"/> for a <see cref="ReaderWriterLockSlim"/>.
  126. /// </summary>
  127. /// <param name="rwl">the lock to acquire in write mode</param>
  128. /// <returns>the locker to use with <see langword="using"/></returns>
  129. public static IReadWriteLocker LockWrite(ReaderWriterLockSlim rwl) => new ReaderWriterLockSlimWriteLocker(rwl);
  130. /// <summary>
  131. /// Creates an <see cref="IReadWriteLocker"/> for a <see cref="ReaderWriterLockSlim"/>.
  132. /// </summary>
  133. /// <param name="rwl">the lock to acquire in read mode</param>
  134. /// <returns>the locker to use with <see langword="using"/></returns>
  135. public static IReadWriteLocker LockRead(ReaderWriterLockSlim rwl) => new ReaderWriterLockSlimReadLocker(rwl);
  136. /// <summary>
  137. /// Creates an <see cref="IUpgradableLocker"/> for a <see cref="ReaderWriterLockSlim"/>.
  138. /// </summary>
  139. /// <param name="rwl">the lock to acquire in upgradable read mode</param>
  140. /// <returns>the locker to use with <see langword="using"/></returns>
  141. public static IUpgradableLocker LockReadUpgradable(ReaderWriterLockSlim rwl) => new ReaderWriterLockSlimUpgradableReadLocker(rwl);
  142. #endregion
  143. }
  144. }