using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; #if NET3 using Net3_Proxy; #endif namespace IPA.Utilities.Async { /// /// Utilities for inter-thread synchronization. All Locker method acquire their object immediately, /// and should only be used with to automatically release them. /// /// /// /// The canonical usage of *all* of the member functions is as follows, substituting /// with whichever member you want to use, according to your lock type. /// /// /// using var _locker = Synchronization.Lock(mutex); /// /// public static class Synchronization { #region Locker structs /// /// A locker for a that automatically releases when it is disposed. /// Create this with . /// /// /// public struct MutexLocker : IDisposable { private readonly Mutex mutex; internal MutexLocker(Mutex mutex) { this.mutex = mutex; mutex.WaitOne(); // wait and acquire mutex } void IDisposable.Dispose() => mutex.ReleaseMutex(); // release mutex } /// /// A locker for a that automatically releases when it is disposed. /// Create this with . /// /// /// public struct SemaphoreLocker : IDisposable { private readonly Semaphore sem; internal SemaphoreLocker(Semaphore sem) { this.sem = sem; sem.WaitOne(); } void IDisposable.Dispose() => sem.Release(); } /// /// A locker for a that automatically releases when it is disposed. /// Create this with . /// /// /// public struct SemaphoreSlimLocker : IDisposable { private readonly SemaphoreSlim sem; internal SemaphoreSlimLocker(SemaphoreSlim sem) { this.sem = sem; sem.Wait(); } void IDisposable.Dispose() => sem.Release(); } #if NET4 /// /// A locker for a that was created asynchronously and automatically releases /// when it is disposed. Create this with . /// /// /// public struct SemaphoreSlimAsyncLocker : IDisposable { private readonly SemaphoreSlim sem; internal SemaphoreSlimAsyncLocker(SemaphoreSlim sem) => this.sem = sem; internal Task Lock() => sem.WaitAsync(); void IDisposable.Dispose() => sem.Release(); } #endif /// /// A locker for a write lock on a that automatically releases when /// it is disposed. Create this with . /// /// /// public struct ReaderWriterLockSlimWriteLocker : IDisposable { private readonly ReaderWriterLockSlim rwl; internal ReaderWriterLockSlimWriteLocker(ReaderWriterLockSlim lck) { rwl = lck; rwl.EnterWriteLock(); } void IDisposable.Dispose() => rwl.ExitWriteLock(); } /// /// A locker for a read lock on a that automatically releases when /// it is disposed. Create this with . /// /// /// public struct ReaderWriterLockSlimReadLocker : IDisposable { private readonly ReaderWriterLockSlim rwl; internal ReaderWriterLockSlimReadLocker(ReaderWriterLockSlim lck) { rwl = lck; rwl.EnterReadLock(); } void IDisposable.Dispose() => rwl.ExitReadLock(); } /// /// A locker for an upgradable read lock on a that automatically releases /// when it is disposed. Create this with . /// /// /// public struct ReaderWriterLockSlimUpgradableReadLocker : IDisposable { private readonly ReaderWriterLockSlim rwl; internal ReaderWriterLockSlimUpgradableReadLocker(ReaderWriterLockSlim lck) { rwl = lck; rwl.EnterUpgradeableReadLock(); } /// /// Creates a locker for a write lock on the associated with this locker, /// upgrading the current thread's lock. /// /// a locker for the new write lock /// public ReaderWriterLockSlimWriteLocker Upgrade() => new ReaderWriterLockSlimWriteLocker(rwl); void IDisposable.Dispose() => rwl.ExitUpgradeableReadLock(); } #endregion #region Accessors /// /// Creates a locker for a mutex. /// /// the mutex to acquire /// the locker to use with public static MutexLocker Lock(Mutex mut) => new MutexLocker(mut); /// /// Creates a locker for a semaphore. /// /// the semaphore to acquire /// the locker to use with public static SemaphoreLocker Lock(Semaphore sem) => new SemaphoreLocker(sem); /// /// Creates a locker for a slim semaphore. /// /// the slim semaphore to acquire /// the locker to use with public static SemaphoreSlimLocker Lock(SemaphoreSlim sem) => new SemaphoreSlimLocker(sem); #if NET4 // TODO: make this work on NET3 too /// /// Creates a locker for a slim semaphore asynchronously. /// /// the slim semaphore to acquire async /// the locker to use with public static async Task LockAsync(SemaphoreSlim sem) { var locker = new SemaphoreSlimAsyncLocker(sem); await locker.Lock(); return locker; } #endif /// /// Creates a locker for a write lock . /// /// the lock to acquire in write mode /// the locker to use with public static ReaderWriterLockSlimWriteLocker LockWrite(ReaderWriterLockSlim rwl) => new ReaderWriterLockSlimWriteLocker(rwl); /// /// Creates a locker for a read lock on a . /// /// the lock to acquire in read mode /// the locker to use with public static ReaderWriterLockSlimReadLocker LockRead(ReaderWriterLockSlim rwl) => new ReaderWriterLockSlimReadLocker(rwl); /// /// Creates a locker for an upgradable read lock on a . /// /// the lock to acquire in upgradable read mode /// the locker to use with public static ReaderWriterLockSlimUpgradableReadLocker LockReadUpgradable(ReaderWriterLockSlim rwl) => new ReaderWriterLockSlimUpgradableReadLocker(rwl); #endregion } }