Ejemplo n.º 1
0
        private bool EnterIfPossible(T lockingObject, byte lockType, LockRuleset rules, out LockToken <T> token, LockHolder h)
        {
            var entrancePair = rules.LockMatrix.EntrancePair(lockType, h.LockInfo); //найден (или не найден) допустимый переход из текущего состояния блокировок в требуемый тип

            if (entrancePair.HasValue)                                              //если найден
            {
                unchecked
                {
                    var blockExit = (int)entrancePair.Value.BlockExit;
                    Debug.Assert((entrancePair.Value.BlockEntrance & LockMatrix.SharenessCheckLock) == 0, "(entrancePair.Value.BlockEntrance & LockMatrix.SharenessCheckLock) == 0", "Не должно быть флага разделяемой блокировки в допустимом входном состоянии");
                    //делаем непосредственно переход
                    if (Interlocked.CompareExchange(ref h.LockInfo, blockExit, (int)entrancePair.Value.BlockEntrance) == (int)entrancePair.Value.BlockEntrance)
                    {
                        int sharedLockCount = 0;
                        //если взяли разделяемую блокировку с уже существующей
                        if ((blockExit & LockMatrix.SharenessCheckLock) == LockMatrix.SharenessCheckLock)
                        {
                            sharedLockCount = h.IncrLock(rules.LockMatrix.SelfSharedLockShift(lockType));//добавляем счётчик к количеству этих блокировок на заданном типе
                            Debug.Print($"sharedLockCount");
                            Debug.Assert(h.LockInfo == blockExit, "h.LockInfo == blockExit", "Состояние блокировок изменилось там, где не должно");
                            h.LockInfo = (int)((uint)h.LockInfo & LockMatrix.SharenessCheckLockDrop);//и сбрасываем этот флажок обратно. Никто не должен поменять LockInfo, т.к. с этим поднятым флажков не должно быть допустимых состояний.
                        }
                        token = new LockToken <T>(lockType, lockingObject, this, rules, sharedLockCount);
                        return(true);
                    }
                }
            }
            token = default(LockToken <T>);
            return(false);
        }
Ejemplo n.º 2
0
        public bool TryAcqureLock(T lockingObject, LockRuleset rules, byte lockType, out LockToken <T> token)
        {
            var h = _locks.GetOrAdd(lockingObject, _ => new LockHolder(rules.LockMatrix.SelfSharedLocks));

            h.LastUsage = Stopwatch.GetTimestamp();

            return(EnterIfPossible(lockingObject, lockType, rules, out token, h));
        }
 internal LockToken(byte lockLevel, T lockedObject, ILockManager <T> holder, LockRuleset matrix, int sharedLockCount)
 {
     LockLevel       = lockLevel;
     LockedObject    = lockedObject;
     _holder         = holder;
     _matrix         = matrix;
     _isReleased     = 0;
     SharedLockCount = sharedLockCount;
 }
Ejemplo n.º 4
0
        public async Task <LockToken <T> > WaitLock(T lockingObject, LockRuleset rules, byte lockType)
        {
            var h = _locks.GetOrAdd(lockingObject, _ => new LockHolder(rules.LockMatrix.SelfSharedLocks));

            h.LastUsage = Stopwatch.GetTimestamp();
            LockToken <T> token;

            while (!EnterIfPossible(lockingObject, lockType, rules, out token, h))
            {
                await Task.Delay(1);
            }
            return(token);
        }
Ejemplo n.º 5
0
        public void ReleaseLock(LockToken <T> token, LockRuleset rules)
        {
            if (!_locks.TryGetValue(token.LockedObject, out var h))
            {
                throw new InvalidOperationException("Object not locked");
            }
            var lockType = token.LockLevel;
            var matrix   = rules.LockMatrix;

            unchecked
            {
                if (matrix.IsSelfShared(lockType))
                {
                    int i;
                    Thread.BeginCriticalRegion();

                    do                                                             //переводим комбинацию блокировок в новое состояние и поднимаем флаг проверки разделямых блокировок
                    {
                        i = (int)(h.LockInfo & LockMatrix.SharenessCheckLockDrop); //мы исключаем из возможных переходы, результатом которых будет поднятый флаг проверки разделяемой блокировки (проверки разделяемой блокировки смогут пересечься)
                    } while (Interlocked.CompareExchange(ref h.LockInfo, i | (int)LockMatrix.SharenessCheckLock, i) != i);

                    if (h.GetSharedLockCount(matrix.SelfSharedLockShift(lockType)) == 0)//если текущий переход убирает существующую разделяемую блокировку (т.е. их сейчас нет).
                    {
                        //делаем переход в новое состояние
                        h.LockInfo = (int)matrix.ExitPair(lockType, (int)(LockMatrix.SharenessCheckLockDrop & (uint)h.LockInfo)).Value.BlockEntrance;
                    }
                    else//если же видим, что освобождение текущей блокировки только уменьшает количество разделяемых блокировок её типа
                    {
                        var sharedLockCount = h.DecrLock(matrix.SelfSharedLockShift(lockType));//то уменьшаем счётчик блокировок
                        Debug.Print($"{sharedLockCount}");
                        h.LockInfo = h.LockInfo & (int)LockMatrix.SharenessCheckLockDrop;//и сбрасываем флаг проверки
                    }
                    Thread.EndCriticalRegion();
                }
                else
                {
                    while (true)
                    {
                        var entrancePair = matrix.ExitPair(lockType, (int)(h.LockInfo & LockMatrix.SharenessCheckLockDrop));
                        if (entrancePair.HasValue)
                        {
                            if (Interlocked.CompareExchange(ref h.LockInfo, (int)entrancePair.Value.BlockEntrance,
                                                            (int)entrancePair.Value.BlockExit) == (int)entrancePair.Value.BlockExit)
                            {
                                break;
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 6
0
        public bool ChangeLockLevel(ref LockToken <T> token, LockRuleset rules, byte newLevel)
        {
            if (!_locks.TryGetValue(token.LockedObject, out var h))
            {
                throw new InvalidOperationException("Object not locked");
            }
            var matrix         = rules.LockMatrix;
            var excalationPair = matrix.EscalationPairs(token.LockLevel, newLevel)
                                 .Select(k => (LockMatrix.MatrPair?)k)
                                 .FirstOrDefault(k => k.Value.BlockEntrance == h.LockInfo);

            if (excalationPair.HasValue)
            {
                if (Interlocked.CompareExchange(ref h.LockInfo, (int)excalationPair.Value.BlockExit,
                                                (int)excalationPair.Value.BlockEntrance) == excalationPair.Value.BlockEntrance)
                {
                    token = new LockToken <T>(newLevel, token.LockedObject, this, rules, 0);
                    return(true);
                }
            }
            return(false);
        }
        public LockMatrix(LockRuleset rules)
        {
            Debug.Assert(rules.GetLockLevelCount() < 32, "rules.GetLockLevelCount()<32");
            Debug.Assert(rules.GetLockLevelCount() > 0, "rules.GetLockLevelCount()>0");
            byte selfSharedLockShift = 0;

            _lockSelfSharedFlag       = new byte[rules.GetLockLevelCount()];
            _lockSwitchMatrix         = new MatrPair[rules.GetLockLevelCount()][];
            _lockSwitchDictionary     = new IReadOnlyDictionary <int, MatrPair> [rules.GetLockLevelCount()];
            _lockSwitchBackDictionary = new IReadOnlyDictionary <int, MatrPair> [rules.GetLockLevelCount()];
            _lockEscalationMatrix     = new MatrPair[rules.GetLockLevelCount(), rules.GetLockLevelCount()][];
            _singleLockSwitchPaths    = new MatrPair[rules.GetLockLevelCount()];
            var allLockLevels = Enumerable.Range(0, rules.GetLockLevelCount()).ToArray();

            foreach (var lockLevel in allLockLevels)
            {
                _lockEscalationMatrix[lockLevel, lockLevel] = new MatrPair[0];
            }

            var allPossibleStates = Enumerable.Range(0, 1 << (rules.GetLockLevelCount())).ToList();
            var powersOf2         = allLockLevels.Select(k => 1 << k).ToArray();
            var twoBitMatrix      = allLockLevels
                                    .Join(allLockLevels, k => true, k => true, (o, i) => new { o, i })
                                    .Where(k => k.o != k.i)
                                    .Select(k => new { ent = (byte)k.i, ex = (byte)k.o, bits = (1 << k.i) | (1 << k.o) })
                                    .ToArray();

            for (byte i = 0b0; i < rules.GetLockLevelCount(); i++)
            {
                if (rules.AreShared(i, i))
                {
                    _lockSelfSharedFlag[i] = selfSharedLockShift++;
                }
                else
                {
                    _lockSelfSharedFlag[i] = 0xFF;
                }
                for (byte j = 0b0; j < rules.GetLockLevelCount(); j++)
                {
                    if (!rules.AreShared(i, j) && i != j)
                    {
                        var mask = (1 << i) | (1 << j);
                        allPossibleStates.RemoveAll(k => (k & mask) == mask);
                    }
                }
            }

            var possibleLockPath = allPossibleStates
                                   .Join(allPossibleStates, _ => true, _ => true, (o, i) => new{ entrance = (uint)(i), exit = (uint)(o), difference = o ^ i })
                                   .Where(k => k.exit > k.entrance && powersOf2.Contains(k.difference))
                                   .ToArray();

            var possibleEscalationPath = allPossibleStates
                                         .Join(allPossibleStates, k => k != 0, k => k != 0, (o, i) => new { entrance = (uint)(i), exit = (uint)(o), difference = o ^ i })
                                         .Join(twoBitMatrix, k => k.difference, k => k.bits, (o, i) => new { o.entrance, o.exit, escState1 = (uint)i.ent, escState2 = (uint)i.ex })
                                         .Where(k => k.entrance > k.exit && k.escState1 > k.escState2 || k.entrance < k.exit && k.escState1 < k.escState2)
                                         .ToArray();

            var additionalPathsForSelfSharedLocks = Enumerable.Range(0, rules.GetLockLevelCount())
                                                    .Where(k => rules.AreShared((byte)k, (byte)k))
                                                    .Join(allPossibleStates, _ => true, _ => true,
                                                          (o, i) => new { entrance = (uint)i, exit = (uint)i | SharenessCheckLock, difference = i & (1 << o) })
                                                    .Where(k => k.difference != 0)
                                                    .ToArray();

            foreach (var pair in possibleLockPath.Concat(additionalPathsForSelfSharedLocks).GroupBy(k => Array.FindIndex(powersOf2, k2 => k2 == k.difference)))
            {
                _lockSwitchMatrix[pair.Key] = pair.Select(k => new MatrPair(k.entrance, k.exit)).OrderBy(k => k.BlockEntrance).ToArray();
                if (pair.Count() == 1)
                {
                    _singleLockSwitchPaths[pair.Key] = pair.Select(k => new MatrPair(k.entrance, k.exit))
                                                       .Single();
                }
                else
                {
                    _lockSwitchDictionary[pair.Key] = pair
                                                      .Select(k => new MatrPair(k.entrance, k.exit))
                                                      .ToDictionary(k => (int)k.BlockEntrance);
                    _lockSwitchBackDictionary[pair.Key] = pair
                                                          .Select(k => new MatrPair(k.entrance, k.exit))
                                                          .ToDictionary(k => (int)k.BlockExit);
                }
            }


            foreach (var pair in possibleEscalationPath.GroupBy(k => k.escState1))
            {
                foreach (var pair2 in pair.GroupBy(k => k.escState2))
                {
                    _lockEscalationMatrix[pair.Key, pair2.Key] = pair2.Select(k => new MatrPair(k.entrance, k.exit)).ToArray();
                }
            }

            SelfSharedLocks = selfSharedLockShift;
        }
Ejemplo n.º 8
0
        public async Task <LockToken <T> > WaitForLockLevelChange(LockToken <T> token, LockRuleset rules, byte newLevel)
        {
            if (!_locks.TryGetValue(token.LockedObject, out var h))
            {
                throw new InvalidOperationException("Object not locked");
            }
            var matrix = rules.LockMatrix;

            while (true)
            {
                var excalationPair = matrix.EscalationPairs(token.LockLevel, newLevel)
                                     .Select(k => (LockMatrix.MatrPair?)k)
                                     .FirstOrDefault(k => k.Value.BlockEntrance == h.LockInfo);
                if (excalationPair.HasValue)
                {
                    if (Interlocked.CompareExchange(ref h.LockInfo, (int)excalationPair.Value.BlockExit,
                                                    (int)excalationPair.Value.BlockEntrance) == excalationPair.Value.BlockEntrance)
                    {
                        return(new LockToken <T>(newLevel, token.LockedObject, this, rules, 0));
                    }
                }
                await Task.Delay(1);
            }
        }