private static void TryToTransitPersonToTargetSector(TransitionPoolItem transitionItem) { var nextSector = transitionItem.NextSector; var nodeForTransition = nextSector.Map.Transitions .First(x => x.Value.SectorNode.Sector == transitionItem.OldSector).Key; var availableNextNodesToTransition = nextSector.Map.GetNext(nodeForTransition); var allPotentialNodesToTransition = new[] { nodeForTransition }.Concat(availableNextNodesToTransition); var allAvailableNodesToTransition = allPotentialNodesToTransition .Where(x => FilterNodeToTransition(x, nextSector)).ToArray(); var availableNodeToTransition = allAvailableNodesToTransition.FirstOrDefault(); if (availableNodeToTransition is null) { // I dont know what I can do. // I think it was solved when a some transition pool was developed. // Now just return person into old sector in old transition node. nextSector = transitionItem.OldSector; availableNodeToTransition = transitionItem.OldNode; } var actorInNewSector = new Actor(transitionItem.Person, transitionItem.TaskSource, availableNodeToTransition); nextSector.ActorManager.Add(actorInNewSector); }
private async Task ProcessInnerAsync(IGlobe globe, ISector sector, IActor actor, SectorTransition transition) { var sectorNode = transition.SectorNode; //TODO Разобраться с этим кодом. // https://blog.cdemi.io/async-waiting-inside-c-sharp-locks/ //Asynchronously wait to enter the Semaphore. If no-one has been granted access to the Semaphore, code execution will proceed, otherwise this thread waits here until the semaphore is released #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task await _semaphoreSlim.WaitAsync(); #pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task try { if (sectorNode.State != SectorNodeState.SectorMaterialized) { await _globeExpander.ExpandAsync(sectorNode).ConfigureAwait(false); globe.AddSectorNode(sectorNode); } // It was used as fallback later. var oldActorNode = actor.Node; try { sector.ActorManager.Remove(actor); } catch (InvalidOperationException exception) { // Пока ничего не делаем Console.WriteLine(exception); Console.WriteLine(sector.GetHashCode()); Console.WriteLine(actor); } var nextSector = sectorNode.Sector; var transitionItem = new TransitionPoolItem(actor.Person, actor.TaskSource, nextSector, sector, oldActorNode); _transitionPool.Push(transitionItem); } finally { //When the task is ready, release the semaphore. It is vital to ALWAYS release the semaphore when we are ready, or else we will end up with a Semaphore that is forever locked. //This is why it is important to do the Release within a try...finally clause; program execution may crash or take a different path, this way you are guaranteed execution _semaphoreSlim.Release(); } }
private async Task ProcessInternalAsync(IGlobe globe, ISector sourceSector, IActor actor, SectorTransition transition) { var sectorNode = transition.SectorNode; await _semaphoreSlim.WaitAsync().ConfigureAwait(false); try { if (sectorNode.State != SectorNodeState.SectorMaterialized) { await _globeExpander.ExpandAsync(sectorNode).ConfigureAwait(false); globe.AddSectorNode(sectorNode); } // It was used as fallback later. var oldActorNode = actor.Node; sourceSector.ActorManager.Remove(actor); var targetSector = sectorNode.Sector; if (targetSector is null) { throw new InvalidOperationException(); } var transitionItem = new TransitionPoolItem( actor.Person, actor.TaskSource, targetSector, sourceSector, oldActorNode); _transitionPool.Push(transitionItem); } finally { //When the task is ready, release the semaphore. It is vital to ALWAYS release the semaphore when we are ready, or else we will end up with a Semaphore that is forever locked. //This is why it is important to do the Release within a try...finally clause; program execution may crash or take a different path, this way you are guaranteed execution _semaphoreSlim.Release(); } }
public void UpdateTransitions() { // The counter is restriction of transition per globe iteration. var counter = TransitionPerGlobeIteration; TransitionPoolItem transitionItem = null; // Transit persons from pool to target sector levels while the pool is not empty or transition limit reached. do { transitionItem = _transitionPool.Pop(); if (transitionItem is null) { return; } TryToTransitPersonToTargetSector(transitionItem); counter--; } while (counter > 0); }
public void Push(TransitionPoolItem poolItem) { _queue.Enqueue(poolItem); }