예제 #1
0
        /// <summary>
        ///     Converts the ownership mode from shared
        ///     to exclusive.
        /// </summary>
        public void ConvertSharedToExclusive()
        {
            int i = 0;

#if ENABLE_STATISTICS
            Interlocked.Increment(ref _cvtExclCount);
#endif

            while (true)
            {
                int value = _value;

#if RIGOROUS_CHECKS
                Trace.Assert((value & LockOwned) != 0);
                Trace.Assert((value & LockExclusiveWaking) == 0);
                Trace.Assert(((value >> LockSharedOwnersShift) & LockSharedOwnersMask) != 0);
#endif

                // Case 1: We are the last shared owner
                if (((value >> LockSharedOwnersShift) & LockSharedOwnersMask) == 1)
                {
                    if (Interlocked.CompareExchange(ref _value, value - LockSharedOwnersIncrement, value) == value)
                    {
                        return;
                    }
                }
                // Case 2: There are still other shared owners
                else if (i >= SpinCount)
                {
#if DEFER_EVENT_CREATION
                    // This call must go *before* the next operation. Otherwise,
                    // we will have a race condition between potential releasers
                    // and us.
                    EnsureEventCreated(ref _convertToExclusiveWakeEvent);
#endif
                    if (Interlocked.CompareExchange(ref _value, value - LockSharedOwnersIncrement + LockConvertToExclusiveWaitersIncrement, value) == value)
                    {
#if ENABLE_STATISTICS
                        Interlocked.Increment(ref _cvtExclSlpCount);

                        int cvtExclWtrsCount = (value >> LockConvertToExclusiveWaitersShift) & LockConvertToExclusiveWaitersMask;

                        Interlocked2.Set(
                            ref _peakCvtExclWtrsCount,
                            p => p < cvtExclWtrsCount,
                            p => cvtExclWtrsCount
                            );
#endif
                        // Go to sleep.
                        if (!_convertToExclusiveWakeEvent.WaitOne())
                        {
                            Break(MsgFailedToWaitIndefinitely);
                        }

                        // Acquire the lock.
                        // At this point *no one* should be able to steal the lock from us.
                        do
                        {
                            value = _value;
#if RIGOROUS_CHECKS
                            Trace.Assert((value & LockOwned) == 0);
                            Trace.Assert((value & LockExclusiveWaking) != 0);
#endif
                        }while (Interlocked.CompareExchange(ref _value, value + LockOwned - LockExclusiveWaking, value) != value);

                        break;
                    }
                }

#if ENABLE_STATISTICS
                Interlocked.Increment(ref _acqExclContCount);
#endif
                i++;
            }
        }
예제 #2
0
        /// <summary>
        ///     Acquires the lock in exclusive mode, blocking
        ///     if necessary.
        /// </summary>
        /// <remarks>
        ///     Exclusive acquires are given precedence over shared
        ///     acquires.
        /// </remarks>
        public IDisposable AcquireExclusive()
        {
            int i = 0;

#if ENABLE_STATISTICS
            Interlocked.Increment(ref _acqExclCount);
#endif
            while (true)
            {
                int value = _value;

                // Case 1: lock not owned AND an exclusive waiter is not waking up.
                // Here we don't have to check if there are exclusive waiters, because
                // if there are the lock would be owned, and we are checking that anyway.
                if ((value & (LockOwned | LockExclusiveWaking)) == 0)
                {
#if RIGOROUS_CHECKS
                    Trace.Assert(((value >> LockSharedOwnersShift) & LockSharedOwnersMask) == 0);
                    Trace.Assert(((value >> LockExclusiveWaitersShift) & LockExclusiveWaitersMask) == 0);
                    Trace.Assert(((value >> LockConvertToExclusiveWaitersShift) & LockConvertToExclusiveWaitersMask) == 0);
#endif
                    if (Interlocked.CompareExchange(ref _value, value + LockOwned, value) == value)
                    {
                        break;
                    }
                }

                // Case 2: lock owned OR lock not owned and an exclusive waiter is waking up
                // The second case means an exclusive waiter has just been woken up and is
                // going to acquire the lock. We have to go to sleep to make sure we don't
                // steal the lock.
                else if (i >= SpinCount)
                {
#if DEFER_EVENT_CREATION
                    // This call must go *before* the next operation. Otherwise,
                    // we will have a race condition between potential releasers
                    // and us.
                    EnsureEventCreated(ref _exclusiveWakeEvent);
#endif
                    if (Interlocked.CompareExchange(ref _value, value + LockExclusiveWaitersIncrement, value) == value)
                    {
#if ENABLE_STATISTICS
                        Interlocked.Increment(ref _acqExclSlpCount);

                        int exclWtrsCount = (value >> LockExclusiveWaitersShift) & LockExclusiveWaitersMask;

                        Interlocked2.Set(
                            ref _peakExclWtrsCount,
                            p => p < exclWtrsCount,
                            p => exclWtrsCount
                            );
#endif
                        // Go to sleep.
                        if (!_exclusiveWakeEvent.WaitOne())
                        {
                            Break(MsgFailedToWaitIndefinitely);
                        }

                        // Acquire the lock.
                        // At this point *no one* should be able to steal the lock from us.
                        do
                        {
                            value = _value;
#if RIGOROUS_CHECKS
                            Trace.Assert((value & LockOwned) == 0);
                            Trace.Assert((value & LockExclusiveWaking) != 0);
#endif
                        }while (Interlocked.CompareExchange(ref _value, value + LockOwned - LockExclusiveWaking, value) != value);

                        break;
                    }
                }

#if ENABLE_STATISTICS
                Interlocked.Increment(ref _acqExclContCount);
#endif
                i++;
            }

            return(_fastResourceLockContext);
        }
예제 #3
0
        /// <summary>
        ///     Acquires the lock in shared mode, blocking
        ///     if necessary.
        /// </summary>
        /// <remarks>
        ///     Exclusive acquires are given precedence over shared
        ///     acquires.
        /// </remarks>
        public IDisposable AcquireShared()
        {
            int i = 0;

#if ENABLE_STATISTICS
            Interlocked.Increment(ref _acqShrdCount);
#endif
            while (true)
            {
                int value = _value;

                // Case 1: lock not owned AND no exclusive waiter is waking up AND
                // there are no shared owners AND there are no exclusive waiters AND no convert to exclusive is waiting
                if ((value & (LockOwned | (LockSharedOwnersMask << LockSharedOwnersShift) | ExclusiveMask)) == 0)
                {
                    if (Interlocked.CompareExchange(ref _value, value + LockOwned + LockSharedOwnersIncrement, value) == value)
                    {
                        break;
                    }
                }
                // Case 2: lock is owned AND no exclusive waiter is waking up AND
                // there are shared owners AND there are no exclusive waiters AND no convert to exclusive is waiting
                else if ((value & LockOwned) != 0 && ((value >> LockSharedOwnersShift) & LockSharedOwnersMask) != 0 && (value & ExclusiveMask) == 0)
                {
                    if (Interlocked.CompareExchange(ref _value, value + LockSharedOwnersIncrement, value) == value)
                    {
                        break;
                    }
                }
                // Other cases.
                else if (i >= SpinCount)
                {
#if DEFER_EVENT_CREATION
                    EnsureEventCreated(ref _sharedWakeEvent);
#endif
                    if (Interlocked.CompareExchange(ref _value, value + LockSharedWaitersIncrement, value) == value)
                    {
#if ENABLE_STATISTICS
                        Interlocked.Increment(ref _acqShrdSlpCount);

                        int shrdWtrsCount = (value >> LockSharedWaitersShift) & LockSharedWaitersMask;

                        Interlocked2.Set(
                            ref _peakShrdWtrsCount,
                            p => p < shrdWtrsCount,
                            p => shrdWtrsCount
                            );
#endif
                        // Go to sleep.
                        if (!_sharedWakeEvent.WaitOne())
                        {
                            Break(MsgFailedToWaitIndefinitely);
                        }

                        // Go back and try again.
                        continue;
                    }
                }

#if ENABLE_STATISTICS
                Interlocked.Increment(ref _acqShrdContCount);
#endif
                i++;
            }

            return(_fastResourceLockContext);
        }
        /// <summary>
        /// Acquires the lock in shared mode, blocking
        /// if necessary.
        /// </summary>
        /// <remarks>
        /// Exclusive acquires are given precedence over shared
        /// acquires.
        /// </remarks>
        public void AcquireShared()
        {
            int value;
            int i = 0;

#if ENABLE_STATISTICS
            Interlocked.Increment(ref _acqShrdCount);
#endif
            while (true)
            {
                value = _value;

                // Case 1: lock not owned AND no exclusive waiter is waking up AND
                // there are no shared owners AND there are no exclusive waiters
                if ((value & (
                         LockOwned |
                         (LockSharedOwnersMask << LockSharedOwnersShift) |
                         ExclusiveMask
                         )) == 0)
                {
                    if (Interlocked.CompareExchange(
                            ref _value,
                            value + LockOwned + LockSharedOwnersIncrement,
                            value
                            ) == value)
                    {
                        break;
                    }
                }
                // Case 2: lock is owned AND no exclusive waiter is waking up AND
                // there are shared owners AND there are no exclusive waiters
                else if (
                    (value & LockOwned) != 0 &&
                    ((value >> LockSharedOwnersShift) & LockSharedOwnersMask) != 0 &&
                    (value & ExclusiveMask) == 0
                    )
                {
                    if (Interlocked.CompareExchange(
                            ref _value,
                            value + LockSharedOwnersIncrement,
                            value
                            ) == value)
                    {
                        break;
                    }
                }
                // Other cases.
                else if (i >= SpinCount)
                {
#if DEFER_EVENT_CREATION
                    this.EnsureEventCreated(ref _sharedWakeEvent);
#endif
                    if (Interlocked.CompareExchange(
                            ref _value,
                            value + LockSharedWaitersIncrement,
                            value
                            ) == value)
                    {
#if ENABLE_STATISTICS
                        Interlocked.Increment(ref _acqShrdSlpCount);

                        int shrdWtrsCount = (value >> LockSharedWaitersShift) & LockSharedWaitersMask;

                        Interlocked2.Set(
                            ref _peakShrdWtrsCount,
                            p => p < shrdWtrsCount,
                            p => shrdWtrsCount
                            );
#endif
                        // Go to sleep.
                        if (NativeMethods.WaitForSingleObject(
                                _sharedWakeEvent,
                                Timeout.Infinite
                                ) != NativeMethods.WaitObject0)
                        {
                            Utils.Break(Utils.MsgFailedToWaitIndefinitely);
                        }

                        // Go back and try again.
                        continue;
                    }
                }

#if ENABLE_STATISTICS
                Interlocked.Increment(ref _acqShrdContCount);
#endif
                i++;
            }
        }