System.Threading.ReaderWriterLock.ReleaseReaderLock C# (CSharp) Method

ReleaseReaderLock() public method

public ReleaseReaderLock ( ) : void
return void
        public void ReleaseReaderLock()
        {
            // Check if the thread has writer lock
            if (_writerID == GetCurrentThreadID())
            {
                ReleaseWriterLock();
                return;
            }

            ThreadLocalLockEntry threadLocalLockEntry = ThreadLocalLockEntry.GetCurrent(_lockID);
            if (threadLocalLockEntry == null)
            {
                throw GetNotOwnerException();
            }

            Debug.Assert((_state & LockStates.Writer) == 0);
            Debug.Assert((_state & LockStates.ReadersMask) != 0);
            Debug.Assert(threadLocalLockEntry._readerLevel > 0);

            --threadLocalLockEntry._readerLevel;
            if (threadLocalLockEntry._readerLevel > 0)
            {
                return;
            }

            // Not a reader any more
            bool isLastReader;
            bool cacheEvents;
            AutoResetEvent writerEvent = null;
            ManualResetEventSlim readerEvent = null;
            int currentState = _state;
            int knownState;
            do
            {
                isLastReader = false;
                cacheEvents = false;
                knownState = currentState;
                int modifyState = -LockStates.Reader;

                if ((knownState & (LockStates.ReadersMask | LockStates.ReaderSignaled)) == LockStates.Reader)
                {
                    isLastReader = true;
                    if ((knownState & LockStates.WaitingWritersMask) != 0)
                    {
                        writerEvent = TryGetOrCreateWriterEvent();
                        if (writerEvent == null)
                        {
                            // Similar to below, wait for some time and try again
                            Helpers.Sleep(100);
                            currentState = _state;
                            knownState = 0;
                            Debug.Assert(currentState != knownState);
                            continue;
                        }
                        modifyState += LockStates.WriterSignaled;
                    }
                    else if ((knownState & LockStates.WaitingReadersMask) != 0)
                    {
                        readerEvent = TryGetOrCreateReaderEvent();
                        if (readerEvent == null)
                        {
                            // Wait for some time and try again. Since a WaitingReaders bit is set, the event would usually
                            // already be created (if the waiting reader that called AcquireReaderLock is already waiting on the
                            // event, it would have created the event). However, AcquireReaderLock adds WaitingReader to the
                            // state before trying to create the event.
                            //
                            // This is such a situation, where the event has not yet been created, and likely due to the system
                            // being low on resources, this thread failed to create the event. We don't want to throw here,
                            // because it could potentially leave waiters waiting and cause a deadlock.
                            //
                            // Instead, we let the threads that set the WaitingReader bit throw, and here, just wait and try
                            // again. In a low-resource situation, eventually, all such new waiting readers would throw, and the
                            // WaitingReaders bits would not be set anymore, breaking the loop and releasing this thread.
                            Helpers.Sleep(100);
                            currentState = _state;
                            knownState = 0;
                            Debug.Assert(currentState != knownState);
                            continue;
                        }
                        modifyState += LockStates.ReaderSignaled;
                    }
                    else if (knownState == LockStates.Reader && (_readerEvent != null || _writerEvent != null))
                    {
                        cacheEvents = true;
                        modifyState += LockStates.CachingEvents;
                    }
                }

                Debug.Assert((knownState & LockStates.Writer) == 0);
                Debug.Assert((knownState & LockStates.ReadersMask) != 0);
                currentState = Interlocked.CompareExchange(ref _state, knownState + modifyState, knownState);
            } while (currentState != knownState);

            // Check for last reader
            if (isLastReader)
            {
                // Check for waiting writers
                if ((knownState & LockStates.WaitingWritersMask) != 0)
                {
                    Debug.Assert((_state & LockStates.WriterSignaled) != 0);
                    Debug.Assert(writerEvent != null);
                    writerEvent.Set();
                }
                // Check for waiting readers
                else if ((knownState & LockStates.WaitingReadersMask) != 0)
                {
                    Debug.Assert((_state & LockStates.ReaderSignaled) != 0);
                    Debug.Assert(readerEvent != null);
                    readerEvent.Set();
                }
                // Check for the need to release events
                else if (cacheEvents)
                {
                    ReleaseEvents();
                }
            }

            Debug.Assert(threadLocalLockEntry.IsFree);
        }

Usage Example

        public static Command DoActionWithReaderLock(Func <Command> funcToRun)
        {
            Command found   = null;
            bool    hadLock = false;

            if (_lock.IsWriterLockHeld || _lock.IsReaderLockHeld)
            {
                //use it;
                hadLock = true;
            }
            else
            {
                _lock.AcquireReaderLock(_writerLockTimeoutMs);
            }

            if (!_lock.IsReaderLockHeld)
            {
                throw new ApplicationException("Unable to acquire Reader lock on CommandQueue (to return single) after waiting " + _writerLockTimeoutMs + " milliseconds.");
            }

            //do the thing
            found = funcToRun();

            if (hadLock)
            {
                //keep it
            }
            else
            {
                //Reset the
                _lock.ReleaseReaderLock();
            }
            return(found);
        }
All Usage Examples Of System.Threading.ReaderWriterLock::ReleaseReaderLock