Esempio n. 1
0
        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();
     }
 }
Esempio n. 5
0
 /// <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);
            }
Esempio n. 9
0
        /// <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));
        }
Esempio n. 10
0
        /// <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));
        }
Esempio n. 13
0
        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);
            }
        }