public void Dispose() { if (_blnIsDisposed) { return; } _blnIsDisposed = true; // Ensure the lock isn't held. If it is, wait for it to be released // before completing the dispose. if (Utils.EverDoEvents) { while (!_objTopLevelSemaphore.Wait(Utils.DefaultSleepDuration)) { Utils.DoEventsSafe(); } } else { _objTopLevelSemaphore.Wait(); } _objTopLevelSemaphore.Release(); if (_blnTopLevelSemaphoreFromPool) { Utils.SemaphorePool.Return(_objTopLevelSemaphore); } else { _objTopLevelSemaphore.Dispose(); } }
/// <summary> /// Try to synchronously obtain a lock for writing. /// The returned SafeSemaphoreWriterRelease must be stored for when the write lock is to be released. /// </summary> public IDisposable EnterWriteLock(CancellationToken token = default) { if (_blnIsDisposed || _blnIsDisposing) { throw new ObjectDisposedException(nameof(AsyncFriendlyReaderWriterLock)); } SemaphoreSlim objCurrentSemaphore = _objCurrentWriterSemaphore.Value ?? _objTopLevelWriterSemaphore; SemaphoreSlim objNextSemaphore = Utils.SemaphorePool.Get(); _objCurrentWriterSemaphore.Value = objNextSemaphore; SafeWriterSemaphoreRelease objReturn = new SafeWriterSemaphoreRelease(objCurrentSemaphore, objNextSemaphore, this); try { if (Utils.EverDoEvents) { while (!objCurrentSemaphore.Wait(Utils.DefaultSleepDuration, token)) { Utils.DoEventsSafe(); } } else { objCurrentSemaphore.Wait(token); } if (Interlocked.Increment(ref _intCountActiveReaders) == 1 && !IsWriteLockHeldRecursively) { try { if (Utils.EverDoEvents) { while (!_objReaderSemaphore.Wait(Utils.DefaultSleepDuration, token)) { Utils.DoEventsSafe(); } } else { _objReaderSemaphore.Wait(token); } } catch { Interlocked.Decrement(ref _intCountActiveReaders); throw; } } } catch { objReturn.Dispose(); throw; } return(objReturn); }
/// <inheritdoc /> public void Dispose() { if (_blnIsDisposed || _blnIsDisposing) { return; } _blnIsDisposing = true; try { // Ensure the locks aren't held. If they are, wait for them to be released // before completing the dispose. if (Utils.EverDoEvents) { while (!_objTopLevelWriterSemaphore.Wait(Utils.DefaultSleepDuration)) { Utils.DoEventsSafe(); } while (!_objReaderSemaphore.Wait(Utils.DefaultSleepDuration)) { Utils.DoEventsSafe(); } } else { _objTopLevelWriterSemaphore.Wait(); _objReaderSemaphore.Wait(); } _objReaderSemaphore.Release(); if (_blnSemaphoresFromPool) { Utils.SemaphorePool.Return(_objReaderSemaphore); } else { _objReaderSemaphore.Dispose(); } SemaphoreSlim objTemp = _objTopLevelWriterSemaphore; _objTopLevelWriterSemaphore = null; objTemp.Release(); if (_blnSemaphoresFromPool) { Utils.SemaphorePool.Return(objTemp); } else { objTemp.Dispose(); } _blnIsDisposed = true; } finally { _blnIsDisposing = false; } }
/// <summary> /// Version of SemaphoreSlim::Wait() that also processes application events if this is called on the UI thread /// </summary> public static void SafeWait(this SemaphoreSlim objSemaphoreSlim, bool blnForceDoEvents = false) { if (Utils.EverDoEvents) { while (!objSemaphoreSlim.Wait(Utils.DefaultSleepDuration)) { Utils.DoEventsSafe(blnForceDoEvents); } } else { objSemaphoreSlim.Wait(); } }
/// <summary> /// Version of ReaderWriterLockSlim::EnterReadLock() that also processes application events if this is called on the UI thread /// </summary> public static void SafeEnterWriteLock(this ReaderWriterLockSlim rwlLockerObject, bool blnForceDoEvents = false) { if (Utils.EverDoEvents) { while (!rwlLockerObject.TryEnterWriteLock(Utils.DefaultSleepDuration)) { Utils.DoEventsSafe(blnForceDoEvents); } } else { rwlLockerObject.EnterWriteLock(); } }
/// <summary> /// Version of SemaphoreSlim::Wait() that also processes application events if this is called on the UI thread /// </summary> public void SafeWait(CancellationToken token, bool blnForceDoEvents = false) { if (Utils.EverDoEvents) { while (!Wait(Utils.DefaultSleepDuration, token)) { Utils.DoEventsSafe(blnForceDoEvents); } } else { Wait(token); } }
/// <summary> /// Version of SemaphoreSlim::Wait() that also processes application events if this is called on the UI thread /// </summary> public void SafeWait(bool blnForceDoEvents = false) { if (Utils.EverDoEvents) { while (!Wait(Utils.DefaultSleepDuration)) { Utils.DoEventsSafe(blnForceDoEvents); } } else { Wait(); } }
public void DoRelease(bool blnReleaseLock = true) { if (_objReaderWriterLock.IsDisposed) { throw new InvalidOperationException( "Lock object was disposed before a writer lock release object assigned to it"); } if (_objNextWriterSemaphore != _objReaderWriterLock._objCurrentWriterSemaphore.Value) { if (_objReaderWriterLock._objCurrentWriterSemaphore.Value == _objCurrentWriterSemaphore) { throw new InvalidOperationException( "_objNextWriterSemaphore was expected to be the current semaphore. Instead, the old semaphore was never unset."); } if (_objReaderWriterLock._objCurrentWriterSemaphore.Value == null) { throw new InvalidOperationException( "_objNextWriterSemaphore was expected to be the current semaphore. Instead, the current semaphore is null.\n\n" + "This may be because AsyncLocal's control flow is the inverse of what one expects, so acquiring " + "the lock inside a function and then leaving the function before exiting the lock can produce this situation."); } throw new InvalidOperationException("_objNextWriterSemaphore was expected to be the current semaphore"); } _objReaderWriterLock._objCurrentWriterSemaphore.Value = _objCurrentWriterSemaphore == _objReaderWriterLock._objTopLevelWriterSemaphore ? null : _objCurrentWriterSemaphore; if (blnReleaseLock) { if (Utils.EverDoEvents) { while (!_objNextWriterSemaphore.Wait(Utils.DefaultSleepDuration)) { Utils.DoEventsSafe(); } } else { _objNextWriterSemaphore.Wait(); } _objCurrentWriterSemaphore.Release(); _objNextWriterSemaphore.Release(); } Utils.SemaphorePool.Return(_objNextWriterSemaphore); }
/// <summary> /// Version of SemaphoreSlim::Wait() that also processes application events if this is called on the UI thread /// </summary> public static bool SafeWait(this SemaphoreSlim objSemaphoreSlim, TimeSpan timeout, CancellationToken token, bool blnForceDoEvents = false) { if (Utils.EverDoEvents) { for (int i = timeout.Milliseconds; i >= 0; i -= Utils.DefaultSleepDuration) { if (objSemaphoreSlim.Wait(Math.Min(Utils.DefaultSleepDuration, i), token)) { return(true); } Utils.DoEventsSafe(blnForceDoEvents); } return(false); } return(objSemaphoreSlim.Wait(timeout, token)); }
/// <summary> /// Version of SemaphoreSlim::Wait() that also processes application events if this is called on the UI thread /// </summary> public static bool SafeWait(this SemaphoreSlim objSemaphoreSlim, int millisecondsTimeout, bool blnForceDoEvents = false) { if (Utils.EverDoEvents) { for (int i = millisecondsTimeout; i >= 0; i -= Utils.DefaultSleepDuration) { if (objSemaphoreSlim.Wait(Math.Min(Utils.DefaultSleepDuration, i))) { return(true); } Utils.DoEventsSafe(blnForceDoEvents); } return(false); } return(objSemaphoreSlim.Wait(millisecondsTimeout)); }
/// <summary> /// Version of SemaphoreSlim::Wait() that also processes application events if this is called on the UI thread /// </summary> public bool SafeWait(int millisecondsTimeout, CancellationToken token, bool blnForceDoEvents = false) { if (Utils.EverDoEvents) { for (int i = millisecondsTimeout; i >= 0; i -= Utils.DefaultSleepDuration) { if (Wait(Math.Min(Utils.DefaultSleepDuration, i), token)) { return(true); } Utils.DoEventsSafe(blnForceDoEvents); } return(false); } return(Wait(millisecondsTimeout, token)); }
/// <summary> /// Version of SemaphoreSlim::Wait() that also processes application events if this is called on the UI thread /// </summary> public bool SafeWait(TimeSpan timeout, bool blnForceDoEvents = false) { if (Utils.EverDoEvents) { for (int i = timeout.Milliseconds; i >= 0; i -= Utils.DefaultSleepDuration) { if (Wait(Math.Min(Utils.DefaultSleepDuration, i))) { return(true); } Utils.DoEventsSafe(blnForceDoEvents); } return(false); } return(Wait(timeout)); }
public IDisposable TakeLock() { if (_blnIsDisposed) { throw new ObjectDisposedException(nameof(AsyncLock)); } SemaphoreSlim objCurrentSemaphore = _objCurrentSemaphore.Value ?? _objTopLevelSemaphore; SemaphoreSlim objNextSemaphore = Utils.SemaphorePool.Get(); _objCurrentSemaphore.Value = objNextSemaphore; if (Utils.EverDoEvents) { while (!objCurrentSemaphore.Wait(Utils.DefaultSleepDuration)) { Utils.DoEventsSafe(); } } else { objCurrentSemaphore.Wait(); } return(new SafeSemaphoreRelease(objCurrentSemaphore, objNextSemaphore, this)); }
/// <summary> /// Try to synchronously obtain a lock for reading. /// </summary> public void EnterReadLock(CancellationToken token = default) { if (_blnIsDisposed || _blnIsDisposing) { throw new ObjectDisposedException(nameof(AsyncFriendlyReaderWriterLock)); } // Temporarily acquiring a write lock just to mess with the read locks is a bottleneck, so don't do any such setting unless we need it bool blnDoWriterLock = false; SemaphoreSlim objCurrentSemaphore = _objCurrentWriterSemaphore.Value ?? _objTopLevelWriterSemaphore; SemaphoreSlim objNextSemaphore = Utils.SemaphorePool.Get(); _objCurrentWriterSemaphore.Value = objNextSemaphore; SafeWriterSemaphoreRelease objRelease = new SafeWriterSemaphoreRelease(objCurrentSemaphore, objNextSemaphore, this); try { blnDoWriterLock = _objTopLevelWriterSemaphore.CurrentCount == 0; if (blnDoWriterLock) { if (Utils.EverDoEvents) { while (!objCurrentSemaphore.Wait(Utils.DefaultSleepDuration, token)) { Utils.DoEventsSafe(); } } else { objCurrentSemaphore.Wait(token); } } if (Interlocked.Increment(ref _intCountActiveReaders) == 1) { try { if (Utils.EverDoEvents) { while (!_objReaderSemaphore.Wait(Utils.DefaultSleepDuration, token)) { Utils.DoEventsSafe(); } } else { _objReaderSemaphore.Wait(token); } } catch { Interlocked.Decrement(ref _intCountActiveReaders); throw; } } } finally { // Deliberately DoRelease to not decrement the active reader count objRelease.DoRelease(blnDoWriterLock); } }