private void Release(ReadLockInfo lockInfo)
 {
     if (lockInfo.Taken)
     {
         Monitor.Exit(_rlocko);
     }
 }
        public Snapshot CreateSnapshot()
        {
            var lockInfo = new ReadLockInfo();

            try
            {
                Lock(lockInfo);

                // if no next generation is required, and we already have a gen object,
                // use it to create a new snapshot
                if (_nextGen == false && _genObj != null)
                {
                    return(new Snapshot(this, _genObj.GetGenRef()));
                }

                // else we need to try to create a new gen object
                // whether we are wlocked or not, noone can rlock while we do,
                // so _liveGen and _nextGen are safe
                if (_wlocked > 0) // volatile, cannot ++ but could --
                {
                    // write-locked, cannot use latest gen (at least 1) so use previous
                    var snapGen = _nextGen ? _liveGen - 1 : _liveGen;

                    // create a new gen object if we don't already have one
                    // (happens the first time a snapshot is created)
                    if (_genObj == null)
                    {
                        _genObjs.Enqueue(_genObj = new GenObj(snapGen));
                    }

                    // if we have one already, ensure it's consistent
                    else if (_genObj.Gen != snapGen)
                    {
                        throw new PanicException($"The generation {_genObj.Gen} does not equal the snapshot generation {snapGen}");
                    }
                }
                else
                {
                    // not write-locked, can use latest gen (_liveGen), create a corresponding new gen object
                    _genObjs.Enqueue(_genObj = new GenObj(_liveGen));
                    _nextGen = false; // this is the ONLY thing that triggers a _liveGen++
                }

                // so...
                // the genObj has a weak ref to the genRef, and is queued
                // the snapshot has a ref to the genRef, which has a ref to the genObj
                // when the snapshot is disposed, it decreases genObj counter
                // so after a while, one of these conditions is going to be true:
                // - genObj.Count is zero because all snapshots have properly been disposed
                // - genObj.WeakGenRef is dead because all snapshots have been collected
                // in both cases, we will dequeue and collect

                var snapshot = new Snapshot(this, _genObj.GetGenRef());

                // reading _floorGen is safe if _collectTask is null
                if (_collectTask == null && _collectAuto && _liveGen - _floorGen > CollectMinGenDelta)
                {
                    CollectAsyncLocked();
                }

                return(snapshot);
            }
            finally
            {
                Release(lockInfo);
            }
        }
 private void Lock(ReadLockInfo lockInfo)
 {
     Monitor.Enter(_rlocko, ref lockInfo.Taken);
 }
示例#4
0
        public Snapshot CreateSnapshot()
        {
            var lockInfo = new ReadLockInfo();

            try
            {
                Lock(lockInfo);

                // if no next generation is required, and we already have one,
                // use it and create a new snapshot
                if (_nextGen == false && _generationObject != null)
                {
                    return(new Snapshot(this, _generationObject.GetReference()));
                }

                // else we need to try to create a new gen ref
                // whether we are wlocked or not, noone can rlock while we do,
                // so _liveGen and _nextGen are safe
                if (_wlocked > 0) // volatile, cannot ++ but could --
                {
                    // write-locked, cannot use latest gen (at least 1) so use previous
                    var snapGen = _nextGen ? _liveGen - 1 : _liveGen;

                    // create a new gen ref unless we already have it
                    if (_generationObject == null)
                    {
                        _generationObjects.Enqueue(_generationObject = new GenerationObject(snapGen));
                    }
                    else if (_generationObject.Gen != snapGen)
                    {
                        throw new Exception("panic");
                    }
                }
                else
                {
                    // not write-locked, can use latest gen, create a new gen ref
                    _generationObjects.Enqueue(_generationObject = new GenerationObject(_liveGen));
                    _nextGen = false; // this is the ONLY thing that triggers a _liveGen++
                }

                // so...
                // the genRefRef has a weak ref to the genRef, and is queued
                // the snapshot has a ref to the genRef, which has a ref to the genRefRef
                // when the snapshot is disposed, it decreases genRefRef counter
                // so after a while, one of these conditions is going to be true:
                // - the genRefRef counter is zero because all snapshots have properly been disposed
                // - the genRefRef weak ref is dead because all snapshots have been collected
                // in both cases, we will dequeue and collect

                var snapshot = new Snapshot(this, _generationObject.GetReference());

                // reading _floorGen is safe if _collectTask is null
                if (_collectTask == null && _collectAuto && _liveGen - _floorGen > CollectMinGenDelta)
                {
                    CollectAsyncLocked();
                }

                return(snapshot);
            }
            finally
            {
                Release(lockInfo);
            }
        }