using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace IPA.Utilities { /// /// Utilities for inter-thread synchronization. All Locker method acquire their object immediately. /// public static class Synchronization { #region Public types /// /// A synchronization state locker that releases its state when its /// method is called. ALWAYS use with a block or statement. Otherwise, the locker /// may not release the object be released properly. /// public interface ISyncStateLocker : IDisposable { } /// /// A locker type for locks. /// ALWAYS use with a block or statement. Otherwise, the locker /// may not release the object be released properly. /// public interface IReadWriteLocker : ISyncStateLocker { } /// /// An upgradable locker type for . /// ALWAYS use with a block or statement. Otherwise, the locker /// may not release the object be released properly. /// public interface IUpgradableLocker : IReadWriteLocker { /// /// Upgrades the locker and gives a new locker to manage the upgraded lock. /// /// the locker to use with to manage the write lock IReadWriteLocker Upgrade(); } #endregion #region Implementations private sealed class MutexLocker : ISyncStateLocker { private readonly Mutex mutex; public MutexLocker(Mutex mutex) { this.mutex = mutex; mutex.WaitOne(); // wait and acquire mutex } public void Dispose() => mutex.ReleaseMutex(); // release mutex } private sealed class SemaphoreLocker : ISyncStateLocker { private readonly Semaphore sem; public SemaphoreLocker(Semaphore sem) { this.sem = sem; sem.WaitOne(); } public void Dispose() => sem.Release(); } private sealed class SemaphoreSlimLocker : ISyncStateLocker { private readonly SemaphoreSlim sem; public SemaphoreSlimLocker(SemaphoreSlim sem) { this.sem = sem; sem.Wait(); } public void Dispose() => sem.Release(); } private sealed class ReaderWriterLockSlimWriteLocker : IReadWriteLocker { private readonly ReaderWriterLockSlim rwl; public ReaderWriterLockSlimWriteLocker(ReaderWriterLockSlim lck) { rwl = lck; rwl.EnterWriteLock(); } public void Dispose() => rwl.ExitWriteLock(); } private sealed class ReaderWriterLockSlimReadLocker : IReadWriteLocker { private readonly ReaderWriterLockSlim rwl; public ReaderWriterLockSlimReadLocker(ReaderWriterLockSlim lck) { rwl = lck; rwl.EnterReadLock(); } public void Dispose() => rwl.ExitReadLock(); } private sealed class ReaderWriterLockSlimUpgradableReadLocker : IUpgradableLocker { private readonly ReaderWriterLockSlim rwl; public ReaderWriterLockSlimUpgradableReadLocker(ReaderWriterLockSlim lck) { rwl = lck; rwl.EnterUpgradeableReadLock(); } public IReadWriteLocker Upgrade() => new ReaderWriterLockSlimWriteLocker(rwl); public void Dispose() => rwl.ExitUpgradeableReadLock(); } #endregion #region Accessors // TODO: add async fun stuff to this /// /// Creates an for a mutex. /// /// the mutex to acquire /// the locker to use with public static ISyncStateLocker Locker(Mutex mut) => new MutexLocker(mut); /// /// Creates an for a semaphore. /// /// the semaphore to acquire /// the locker to use with public static ISyncStateLocker Locker(Semaphore sem) => new SemaphoreLocker(sem); /// /// Creates an for a slim semaphore. /// /// the slim semaphore to acquire /// the locker to use with public static ISyncStateLocker Locker(SemaphoreSlim sem) => new SemaphoreSlimLocker(sem); /// /// Creates an for a . /// /// the lock to acquire in write mode /// the locker to use with public static IReadWriteLocker LockWrite(ReaderWriterLockSlim rwl) => new ReaderWriterLockSlimWriteLocker(rwl); /// /// Creates an for a . /// /// the lock to acquire in read mode /// the locker to use with public static IReadWriteLocker LockRead(ReaderWriterLockSlim rwl) => new ReaderWriterLockSlimReadLocker(rwl); /// /// Creates an for a . /// /// the lock to acquire in upgradable read mode /// the locker to use with public static IUpgradableLocker LockReadUpgradable(ReaderWriterLockSlim rwl) => new ReaderWriterLockSlimUpgradableReadLocker(rwl); #endregion } }