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