Exemple #1
0
        ReaderWriterLockTracker Factory()
        {
            var created = new ReaderWriterLockTracker(RecursionPolicy);

            if (Debugger.IsAttached)
            {
                created.BeforeDispose += Debug_TrackerDisposedWhileInUse;
            }
            return(created);
        }
Exemple #2
0
        private ReaderWriterLockTracker GetLock(TKey key, LockType type, object context, int?millisecondsTimeout = null, bool throwsOnTimeout = false)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            ReaderWriterLockSlimExensions.ValidateMillisecondsTimeout(millisecondsTimeout);
            Contract.EndContractBlock();

            if (IsDisposed)
            {
                return(null);
            }

            // Need to be able to enter a lock before releasing access in order to prevent removal...
            var r = CleanupManager.ReadValue(
                () =>
            {
                // It is possible that a read could be acquired while disposing just before the dispose.
                if (IsDisposed)
                {
                    return(null);
                }

                // Get a tracker...
                ReaderWriterLockTracker result;
                {
                    // Compare the tracker retrieved with the one created...
                    ReaderWriterLockTracker created = null;
                    do
                    {
                        result = Locks.GetOrAdd(key, k => created = LockPool.Take());
                    }
                    // Safeguard against rare case of when a disposed tracker is retained via an exception (possibly?). :(
                    while (!IsDisposed && result.IsDisposed);


                    // If the one created is not the one retrieved, go ahead and add it to the pool so it doesn't go to waste.
                    if (created != null && created != result)
                    {
                        if (IsDisposed)
                        {
                            created.Dispose();
                        }
                        else
                        {
                            LockPool.Give(created);
                        }
                    }

                    // This should never get out of sync, but just in case...
                    var rlock = result.Lock;
                    if (rlock == null || result.IsDisposed)
                    {
                        Debug.Fail("A lock tracker was retained after it was disposed.");
                        return(null);
                    }
                    else if (Debugger.IsAttached && rlock.RecursionPolicy == LockRecursionPolicy.NoRecursion)
                    {
                        if (rlock.IsWriteLockHeld && type == LockType.Read)
                        {
                            Debugger.Break();                                     //
                        }
                    }
                }

                // Quick check to avoid further processes...
                if (IsDisposed)
                {
                    return(null);
                }

                var lockHeld = false;
                if (!result.Reserve(context))
                {
                    return(null);
                }
                try
                {
                    // result.Lock will only be null if the tracker has been disposed.
                    lockHeld = AcquireLock(result.Lock, type, millisecondsTimeout, throwsOnTimeout);
                }
                catch (LockRecursionException lrex)
                {
                    lrex.WriteToDebug();
                    Debugger.Break();                             // Need to be able to track down source.
                    throw;
                }
                finally
                {
                    if (!lockHeld)
                    {
                        result.Clear(context);
                    }
                }

                return(lockHeld ? result : null);
            });

            // In the rare case that a dispose could be initiated during this ReadValue:
            // We need to not propagate locking...
            if (r == null || !IsDisposed)
            {
                return(r);
            }
            ReleaseLock(r.Lock, type);
            r.Clear(context);

            return(null);
        }