示例#1
0
        private bool TryEnterWriteLockCore(int millisecondsTimeout)
        {
            if (millisecondsTimeout < -1)
            {
                throw new ArgumentOutOfRangeException("millisecondsTimeout");
            }

            if (fDisposed)
            {
                throw new ObjectDisposedException(null);
            }

            int id = Thread.CurrentThread.ManagedThreadId;
            ReaderWriterCount lrwc;
            bool upgradingToWrite = false;

            if (!fIsReentrant)
            {
                if (id == writeLockOwnerId)
                {
                    //Check for AW->AW
                    throw new LockRecursionException(SR.GetString(SR.LockRecursionException_RecursiveWriteNotAllowed));
                }
                else if (id == upgradeLockOwnerId)
                {
                    //AU->AW case is allowed once.
                    upgradingToWrite = true;
                }

                EnterMyLock();
                lrwc = GetThreadRWCount(id, true);

                //Can't acquire write lock with reader lock held.
                if (lrwc != null && lrwc.readercount > 0)
                {
                    ExitMyLock();
                    throw new LockRecursionException(SR.GetString(SR.LockRecursionException_WriteAfterReadNotAllowed));
                }
            }
            else
            {
                EnterMyLock();
                lrwc = GetThreadRWCount(id, false);

                if (id == writeLockOwnerId)
                {
                    lrwc.rc.writercount++;
                    ExitMyLock();
                    return(true);
                }
                else if (id == upgradeLockOwnerId)
                {
                    upgradingToWrite = true;
                }
                else if (lrwc.readercount > 0)
                {
                    //Write locks may not be acquired if only read locks have been
                    //acquired.
                    ExitMyLock();
                    throw new LockRecursionException(SR.GetString(SR.LockRecursionException_WriteAfterReadNotAllowed));
                }
            }

            int  spincount = 0;
            bool retVal    = true;

            for (;;)
            {
                if (IsWriterAcquired())
                {
                    // Good case, there is no contention, we are basically done
                    SetWriterAcquired();
                    break;
                }

                //Check if there is just one upgrader, and no readers.
                //Assumption: Only one thread can have the upgrade lock, so the
                //following check will fail for all other threads that may sneak in
                //when the upgrading thread is waiting.

                if (upgradingToWrite)
                {
                    uint readercount = GetNumReaders();

                    if (readercount == 1)
                    {
                        //Good case again, there is just one upgrader, and no readers.
                        SetWriterAcquired();    // indicate we have a writer.
                        break;
                    }
                    else if (readercount == 2)
                    {
                        if (lrwc != null)
                        {
                            if (IsRwHashEntryChanged(lrwc, id))
                            {
                                lrwc = GetThreadRWCount(id, false);
                            }

                            if (lrwc.readercount > 0)
                            {
                                //This check is needed for EU->ER->EW case, as the owner count will be two.
                                Debug.Assert(fIsReentrant);
                                Debug.Assert(fUpgradeThreadHoldingRead);

                                //Good case again, there is just one upgrader, and no readers.
                                SetWriterAcquired();   // indicate we have a writer.
                                break;
                            }
                        }
                    }
                }

                if (spincount < MaxSpinCount)
                {
                    ExitMyLock();
                    if (millisecondsTimeout == 0)
                    {
                        return(false);
                    }
                    spincount++;
                    SpinWait(spincount);
                    EnterMyLock();
                    continue;
                }

                if (upgradingToWrite)
                {
                    if (waitUpgradeEvent == null)   // Create the needed event
                    {
                        LazyCreateEvent(ref waitUpgradeEvent, true);
                        continue;   // since we left the lock, start over.
                    }

                    Debug.Assert(numWriteUpgradeWaiters == 0, "There can be at most one thread with the upgrade lock held.");

                    retVal = WaitOnEvent(waitUpgradeEvent, ref numWriteUpgradeWaiters, millisecondsTimeout);

                    //The lock is not held in case of failure.
                    if (!retVal)
                    {
                        return(false);
                    }
                }
                else
                {
                    // Drat, we need to wait.  Mark that we have waiters and wait.
                    if (writeEvent == null)     // create the needed event.
                    {
                        LazyCreateEvent(ref writeEvent, true);
                        continue;   // since we left the lock, start over.
                    }

                    retVal = WaitOnEvent(writeEvent, ref numWriteWaiters, millisecondsTimeout);
                    //The lock is not held in case of failure.
                    if (!retVal)
                    {
                        return(false);
                    }
                }
            }

            Debug.Assert((owners & WRITER_HELD) > 0);

            if (fIsReentrant)
            {
                if (IsRwHashEntryChanged(lrwc, id))
                {
                    lrwc = GetThreadRWCount(id, false);
                }
                lrwc.rc.writercount++;
            }

            ExitMyLock();

            writeLockOwnerId = id;

            return(true);
        }
示例#2
0
        private bool TryEnterUpgradeableReadLockCore(int millisecondsTimeout)
        {
            if (millisecondsTimeout < -1)
            {
                throw new ArgumentOutOfRangeException("millisecondsTimeout");
            }

            if (fDisposed)
            {
                throw new ObjectDisposedException(null);
            }

            int id = Thread.CurrentThread.ManagedThreadId;
            ReaderWriterCount lrwc;

            if (!fIsReentrant)
            {
                if (id == upgradeLockOwnerId)
                {
                    //Check for AU->AU
                    throw new LockRecursionException(SR.GetString(SR.LockRecursionException_RecursiveUpgradeNotAllowed));
                }
                else if (id == writeLockOwnerId)
                {
                    //Check for AU->AW
                    throw new LockRecursionException(SR.GetString(SR.LockRecursionException_UpgradeAfterWriteNotAllowed));
                }

                EnterMyLock();
                lrwc = GetThreadRWCount(id, true);
                //Can't acquire upgrade lock with reader lock held.
                if (lrwc != null && lrwc.readercount > 0)
                {
                    ExitMyLock();
                    throw new LockRecursionException(SR.GetString(SR.LockRecursionException_UpgradeAfterReadNotAllowed));
                }
            }
            else
            {
                EnterMyLock();
                lrwc = GetThreadRWCount(id, false);

                if (id == upgradeLockOwnerId)
                {
                    lrwc.rc.upgradecount++;
                    ExitMyLock();
                    return(true);
                }
                else if (id == writeLockOwnerId)
                {
                    //Write lock is already held, Just update the global state
                    //to show presence of upgrader.
                    Debug.Assert((owners & WRITER_HELD) > 0);
                    owners++;
                    upgradeLockOwnerId = id;
                    lrwc.rc.upgradecount++;
                    if (lrwc.readercount > 0)
                    {
                        fUpgradeThreadHoldingRead = true;
                    }
                    ExitMyLock();
                    return(true);
                }
                else if (lrwc.readercount > 0)
                {
                    //Upgrade locks may not be acquired if only read locks have been
                    //acquired.
                    ExitMyLock();
                    throw new LockRecursionException(SR.GetString(SR.LockRecursionException_UpgradeAfterReadNotAllowed));
                }
            }

            bool retVal = true;

            int spincount = 0;

            for (;;)
            {
                //Once an upgrade lock is taken, it's like having a reader lock held
                //until upgrade or downgrade operations are performed.

                if ((upgradeLockOwnerId == -1) && (owners < MAX_READER))
                {
                    owners++;
                    upgradeLockOwnerId = id;
                    break;
                }

                if (spincount < MaxSpinCount)
                {
                    ExitMyLock();
                    if (millisecondsTimeout == 0)
                    {
                        return(false);
                    }
                    spincount++;
                    SpinWait(spincount);
                    EnterMyLock();
                    continue;
                }

                // Drat, we need to wait.  Mark that we have waiters and wait.
                if (upgradeEvent == null)   // Create the needed event
                {
                    LazyCreateEvent(ref upgradeEvent, true);
                    continue;   // since we left the lock, start over.
                }

                //Only one thread with the upgrade lock held can proceed.
                retVal = WaitOnEvent(upgradeEvent, ref numUpgradeWaiters, millisecondsTimeout);
                if (!retVal)
                {
                    return(false);
                }
            }

            if (fIsReentrant)
            {
                //The lock may have been dropped getting here, so make a quick check to see whether some other
                //thread did not grab the entry.
                if (IsRwHashEntryChanged(lrwc, id))
                {
                    lrwc = GetThreadRWCount(id, false);
                }
                lrwc.rc.upgradecount++;
            }

            ExitMyLock();

            return(true);
        }
示例#3
0
        private bool TryEnterReadLockCore(int millisecondsTimeout)
        {
            if (millisecondsTimeout < -1)
            {
                throw new ArgumentOutOfRangeException("millisecondsTimeout");
            }

            if (fDisposed)
            {
                throw new ObjectDisposedException(null);
            }

            ReaderWriterCount lrwc = null;
            int id = Thread.CurrentThread.ManagedThreadId;

            if (!fIsReentrant)
            {
                if (id == writeLockOwnerId)
                {
                    //Check for AW->AR
                    throw new LockRecursionException(SR.GetString(SR.LockRecursionException_ReadAfterWriteNotAllowed));
                }

                EnterMyLock();

                lrwc = GetThreadRWCount(id, false);

                //Check if the reader lock is already acquired. Note, we could
                //check the presence of a reader by not allocating rwc (But that
                //would lead to two lookups in the common case. It's better to keep
                //a count in the struucture).
                if (lrwc.readercount > 0)
                {
                    ExitMyLock();
                    throw new LockRecursionException(SR.GetString(SR.LockRecursionException_RecursiveReadNotAllowed));
                }
                else if (id == upgradeLockOwnerId)
                {
                    //The upgrade lock is already held.
                    //Update the global read counts and exit.

                    lrwc.readercount++;
                    owners++;
                    ExitMyLock();
                    return(true);
                }
            }
            else
            {
                EnterMyLock();
                lrwc = GetThreadRWCount(id, false);
                if (lrwc.readercount > 0)
                {
                    lrwc.readercount++;
                    ExitMyLock();
                    return(true);
                }
                else if (id == upgradeLockOwnerId)
                {
                    //The upgrade lock is already held.
                    //Update the global read counts and exit.
                    lrwc.readercount++;
                    owners++;
                    ExitMyLock();
                    fUpgradeThreadHoldingRead = true;
                    return(true);
                }
                else if (id == writeLockOwnerId)
                {
                    //The write lock is already held.
                    //Update global read counts here,
                    lrwc.readercount++;
                    owners++;
                    ExitMyLock();
                    return(true);
                }
            }

            bool retVal = true;

            int spincount = 0;

            for (;;)
            {
                // We can enter a read lock if there are only read-locks have been given out
                // and a writer is not trying to get in.

                if (owners < MAX_READER)
                {
                    // Good case, there is no contention, we are basically done
                    owners++;       // Indicate we have another reader
                    lrwc.readercount++;
                    break;
                }

                if (spincount < MaxSpinCount)
                {
                    ExitMyLock();
                    if (millisecondsTimeout == 0)
                    {
                        return(false);
                    }
                    spincount++;
                    SpinWait(spincount);
                    EnterMyLock();
                    //The per-thread structure may have been recycled as the lock is released, load again.
                    if (IsRwHashEntryChanged(lrwc, id))
                    {
                        lrwc = GetThreadRWCount(id, false);
                    }
                    continue;
                }

                // Drat, we need to wait.  Mark that we have waiters and wait.
                if (readEvent == null)      // Create the needed event
                {
                    LazyCreateEvent(ref readEvent, false);
                    if (IsRwHashEntryChanged(lrwc, id))
                    {
                        lrwc = GetThreadRWCount(id, false);
                    }
                    continue;   // since we left the lock, start over.
                }

                retVal = WaitOnEvent(readEvent, ref numReadWaiters, millisecondsTimeout);
                if (!retVal)
                {
                    return(false);
                }
                if (IsRwHashEntryChanged(lrwc, id))
                {
                    lrwc = GetThreadRWCount(id, false);
                }
            }

            ExitMyLock();
            return(retVal);
        }