From a5491a99abef760a31e3133f5b60f6b426dbb55c Mon Sep 17 00:00:00 2001 From: Anairkoen Schno Date: Wed, 4 Dec 2019 18:07:05 -0600 Subject: [PATCH] Redid Synchronization utils to use structs for stack allocation --- IPA.Loader/Utilities/Synchronization.cs | 172 +++++++++++++++--------- 1 file changed, 111 insertions(+), 61 deletions(-) diff --git a/IPA.Loader/Utilities/Synchronization.cs b/IPA.Loader/Utilities/Synchronization.cs index f321b6bc..d110b78c 100644 --- a/IPA.Loader/Utilities/Synchronization.cs +++ b/IPA.Loader/Utilities/Synchronization.cs @@ -8,119 +8,157 @@ using System.Threading.Tasks; namespace IPA.Utilities { /// - /// Utilities for inter-thread synchronization. All Locker method acquire their object immediately. + /// 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 Public types + #region Locker structs /// - /// 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. + /// A locker for a that automatically releases when it is disposed. + /// Create this with . /// - 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 + /// + /// + public struct MutexLocker : IDisposable { private readonly Mutex mutex; - public MutexLocker(Mutex mutex) + internal MutexLocker(Mutex mutex) { this.mutex = mutex; mutex.WaitOne(); // wait and acquire mutex } - public void Dispose() => mutex.ReleaseMutex(); // release mutex + void IDisposable.Dispose() => mutex.ReleaseMutex(); // release mutex } - private sealed class SemaphoreLocker : ISyncStateLocker + /// + /// A locker for a that automatically releases when it is disposed. + /// Create this with . + /// + /// + /// + public struct SemaphoreLocker : IDisposable { private readonly Semaphore sem; - public SemaphoreLocker(Semaphore sem) + internal SemaphoreLocker(Semaphore sem) { this.sem = sem; sem.WaitOne(); } - public void Dispose() => sem.Release(); + void IDisposable.Dispose() => sem.Release(); } - private sealed class SemaphoreSlimLocker : ISyncStateLocker + /// + /// A locker for a that automatically releases when it is disposed. + /// Create this with . + /// + /// + /// + public struct SemaphoreSlimLocker : IDisposable { private readonly SemaphoreSlim sem; - public SemaphoreSlimLocker(SemaphoreSlim sem) + internal SemaphoreSlimLocker(SemaphoreSlim sem) { this.sem = sem; sem.Wait(); } - public void Dispose() => sem.Release(); + void IDisposable.Dispose() => sem.Release(); + } + + /// + /// 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(); } - private sealed class ReaderWriterLockSlimWriteLocker : IReadWriteLocker + /// + /// 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; - public ReaderWriterLockSlimWriteLocker(ReaderWriterLockSlim lck) + internal ReaderWriterLockSlimWriteLocker(ReaderWriterLockSlim lck) { rwl = lck; rwl.EnterWriteLock(); } - public void Dispose() => rwl.ExitWriteLock(); + void IDisposable.Dispose() => rwl.ExitWriteLock(); } - private sealed class ReaderWriterLockSlimReadLocker : IReadWriteLocker + /// + /// 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; - public ReaderWriterLockSlimReadLocker(ReaderWriterLockSlim lck) + internal ReaderWriterLockSlimReadLocker(ReaderWriterLockSlim lck) { rwl = lck; rwl.EnterReadLock(); } - public void Dispose() => rwl.ExitReadLock(); + void IDisposable.Dispose() => rwl.ExitReadLock(); } - private sealed class ReaderWriterLockSlimUpgradableReadLocker : IUpgradableLocker + /// + /// 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; - public ReaderWriterLockSlimUpgradableReadLocker(ReaderWriterLockSlim lck) + internal ReaderWriterLockSlimUpgradableReadLocker(ReaderWriterLockSlim lck) { rwl = lck; rwl.EnterUpgradeableReadLock(); } - public IReadWriteLocker Upgrade() => new ReaderWriterLockSlimWriteLocker(rwl); + /// + /// 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); - public void Dispose() => rwl.ExitUpgradeableReadLock(); + void IDisposable.Dispose() => rwl.ExitUpgradeableReadLock(); } #endregion @@ -128,46 +166,58 @@ namespace IPA.Utilities // TODO: add async fun stuff to this /// - /// Creates an for a mutex. + /// Creates a locker for a mutex. /// /// the mutex to acquire /// the locker to use with - public static ISyncStateLocker Locker(Mutex mut) => new MutexLocker(mut); + public static MutexLocker Lock(Mutex mut) => new MutexLocker(mut); /// - /// Creates an for a semaphore. + /// Creates a locker for a semaphore. /// /// the semaphore to acquire /// the locker to use with - public static ISyncStateLocker Locker(Semaphore sem) => new SemaphoreLocker(sem); + public static SemaphoreLocker Lock(Semaphore sem) => new SemaphoreLocker(sem); /// - /// Creates an for a slim semaphore. + /// Creates a locker for a slim semaphore. /// /// the slim semaphore to acquire /// the locker to use with - public static ISyncStateLocker Locker(SemaphoreSlim sem) => new SemaphoreSlimLocker(sem); + public static SemaphoreSlimLocker Lock(SemaphoreSlim sem) => new SemaphoreSlimLocker(sem); + + /// + /// 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; + } /// - /// Creates an for a . + /// Creates a locker for a write lock . /// /// the lock to acquire in write mode /// the locker to use with - public static IReadWriteLocker LockWrite(ReaderWriterLockSlim rwl) => new ReaderWriterLockSlimWriteLocker(rwl); + public static ReaderWriterLockSlimWriteLocker LockWrite(ReaderWriterLockSlim rwl) => new ReaderWriterLockSlimWriteLocker(rwl); /// - /// Creates an for a . + /// Creates a locker for a read lock on a . /// /// the lock to acquire in read mode /// the locker to use with - public static IReadWriteLocker LockRead(ReaderWriterLockSlim rwl) => new ReaderWriterLockSlimReadLocker(rwl); + public static ReaderWriterLockSlimReadLocker LockRead(ReaderWriterLockSlim rwl) => new ReaderWriterLockSlimReadLocker(rwl); /// - /// Creates an for a . + /// 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 IUpgradableLocker LockReadUpgradable(ReaderWriterLockSlim rwl) => new ReaderWriterLockSlimUpgradableReadLocker(rwl); + public static ReaderWriterLockSlimUpgradableReadLocker LockReadUpgradable(ReaderWriterLockSlim rwl) => new ReaderWriterLockSlimUpgradableReadLocker(rwl); #endregion } }