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); }
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; }
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); }
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; } } } } } }
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; }
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); } }