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
}
}