From 54d732ccd0277a278539b2ab97da1e966c81aeb1 Mon Sep 17 00:00:00 2001 From: Anairkoen Schno Date: Tue, 3 Dec 2019 22:54:32 -0600 Subject: [PATCH] Added some synchronization helpers --- IPA.Loader/IPA.Loader.csproj | 5 + IPA.Loader/Utilities/Synchronization.cs | 173 ++++++++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 IPA.Loader/Utilities/Synchronization.cs diff --git a/IPA.Loader/IPA.Loader.csproj b/IPA.Loader/IPA.Loader.csproj index b689ce82..da6512b1 100644 --- a/IPA.Loader/IPA.Loader.csproj +++ b/IPA.Loader/IPA.Loader.csproj @@ -87,6 +87,7 @@ + @@ -138,6 +139,7 @@ + @@ -172,5 +174,8 @@ + + + \ No newline at end of file diff --git a/IPA.Loader/Utilities/Synchronization.cs b/IPA.Loader/Utilities/Synchronization.cs new file mode 100644 index 00000000..f321b6bc --- /dev/null +++ b/IPA.Loader/Utilities/Synchronization.cs @@ -0,0 +1,173 @@ +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 + } +}