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