public UncheckedReaderWriterLock()
 {
     this.sentinelToken = new WaitingToken();
     this.innerLock = new LightweightSpinLock();
     this.id = Interlocked.Increment(ref counter);
     this.readerCount = 0;
     this.writerPending = 0;
 }
 public UncheckedReaderWriterLock()
 {
     this.sentinelToken = new WaitingToken();
     this.innerLock     = new LightweightSpinLock();
     this.id            = Interlocked.Increment(ref counter);
     this.readerCount   = 0;
     this.writerPending = 0;
 }
        public void EnterWrite()
        {
            // Indicate that a writer operation entered
            Interlocked.CompareExchange(ref this.writerPending, 1, 0);

            // Allocate wait token
            WaitingToken wait = this.AllocateWaitingToken();

            this.WaitForWrite(wait);
        }
        private void WaitForWrite(WaitingToken wait)
        {
            int retry = 0;

            while (true)
            {
                // Check if out token is the next and all readers has left
                if (Interlocked.CompareExchange(ref this.sentinelToken.Next, wait, wait) == wait &&
                    Interlocked.CompareExchange(ref this.readerCount, 0, 0) == 0)
                {
                    return;
                }

                LightweightSpinLock.SpinWait(ref retry);
            }
        }
        private void DropWaitingToken()
        {
            this.innerLock.Enter();

            // sentinelToken.next = current token (it should not be null)
            WaitingToken next = this.sentinelToken.Next.Next;

            this.sentinelToken.Next = next;

            if (next == null)
            {
                // Indicat that no operation wants to write anymore
                Interlocked.CompareExchange(ref this.writerPending, 0, 1);
            }

            this.innerLock.Exit();
        }
        private WaitingToken AllocateWaitingToken()
        {
            WaitingToken wait = new WaitingToken();

            this.innerLock.Enter();

            // Find the last token
            WaitingToken last = this.sentinelToken;

            while (last.Next != null)
            {
                last = last.Next;
            }

            // Concat to the end
            last.Next = wait;

            this.innerLock.Exit();
            return(wait);
        }
        private WaitingToken AllocateWaitingToken()
        {
            WaitingToken wait = new WaitingToken();

            this.innerLock.Enter();

            // Find the last token
            WaitingToken last = this.sentinelToken;

            while (last.Next != null)
            {
                last = last.Next;
            }

            // Concat to the end
            last.Next = wait;

            this.innerLock.Exit();
            return wait;
        }
        private void WaitForWrite(WaitingToken wait)
        {
            int retry = 0;
            while (true)
            {
                // Check if out token is the next and all readers has left
                if (Interlocked.CompareExchange(ref this.sentinelToken.Next, wait, wait) == wait &&
                    Interlocked.CompareExchange(ref this.readerCount, 0, 0) == 0)
                {
                    return;
                }

                LightweightSpinLock.SpinWait(ref retry);
            }
        }