Changeset 16779 for trunk/HeuristicLab.ExtLibs/HeuristicLab.SimSharp/3.1.1/SimSharp-3.1.1/Core/Resources/PreemptiveResource.cs
- Timestamp:
- 04/12/19 13:45:11 (5 years ago)
- Location:
- trunk/HeuristicLab.ExtLibs/HeuristicLab.SimSharp/3.1.1
- Files:
-
- 1 edited
- 1 copied
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/HeuristicLab.ExtLibs/HeuristicLab.SimSharp/3.1.1/SimSharp-3.1.1/Core/Resources/PreemptiveResource.cs
r15972 r16779 1 1 #region License Information 2 2 /* SimSharp - A .NET port of SimPy, discrete event simulation framework 3 Copyright (C) 201 6Heuristic and Evolutionary Algorithms Laboratory (HEAL)3 Copyright (C) 2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL) 4 4 5 5 This program is free software: you can redistribute it and/or modify … … 22 22 23 23 namespace SimSharp { 24 /// <summary> 25 /// A PreemptiveResource is similar to a <see cref="PriorityResource"/>. However, 26 /// it may be possible to interrupt a lower-priority user and hand over the resource. 27 /// 28 /// PreemptiveResource holds a fixed amount of anonymous entities. 29 /// Requests are processed in this order: priority, time, preemption, and finally FIFO. 30 /// Releases are processed in FIFO order (usually no simulation time passes for a Release). 31 /// </summary> 32 /// <remarks> 33 /// Working with PreemptiveResource, a process holding a request must always call 34 /// <see cref="Process.HandleFault"/> after yielding an event and handle a potential 35 /// interruption. 36 /// </remarks> 24 37 public class PreemptiveResource { 25 38 … … 30 43 public int Remaining { get { return Capacity - InUse; } } 31 44 32 protected EnvironmentEnvironment { get; private set; }33 34 protected S ortedList<int, LinkedList<PreemptiveRequest>> RequestQueue { get; private set; }45 protected Simulation Environment { get; private set; } 46 47 protected SimplePriorityQueue<PreemptiveRequest> RequestQueue { get; private set; } 35 48 protected Queue<Release> ReleaseQueue { get; private set; } 36 protected HashSet<Request> Users { get; private set; } 37 38 public PreemptiveResource(Environment environment, int capacity = 1) { 49 protected HashSet<PreemptiveRequest> Users { get; private set; } 50 protected List<Event> WhenAnyQueue { get; private set; } 51 protected List<Event> WhenFullQueue { get; private set; } 52 protected List<Event> WhenEmptyQueue { get; private set; } 53 protected List<Event> WhenChangeQueue { get; private set; } 54 55 public PreemptiveResource(Simulation environment, int capacity = 1) { 39 56 if (capacity <= 0) throw new ArgumentException("Capacity must be > 0.", "capacity"); 40 57 Environment = environment; 41 58 Capacity = capacity; 42 RequestQueue = new S ortedList<int, LinkedList<PreemptiveRequest>>();59 RequestQueue = new SimplePriorityQueue<PreemptiveRequest>(); 43 60 ReleaseQueue = new Queue<Release>(); 44 Users = new HashSet<Request>(); 45 } 46 47 public virtual PreemptiveRequest Request(int priority = 1, bool preempt = false) { 61 Users = new HashSet<PreemptiveRequest>(); 62 WhenAnyQueue = new List<Event>(); 63 WhenFullQueue = new List<Event>(); 64 WhenEmptyQueue = new List<Event>(); 65 WhenChangeQueue = new List<Event>(); 66 } 67 68 public virtual PreemptiveRequest Request(double priority = 1, bool preempt = false) { 48 69 var request = new PreemptiveRequest(Environment, TriggerRelease, DisposeCallback, priority, preempt); 49 if (!RequestQueue.ContainsKey(request.Priority)) 50 RequestQueue.Add(request.Priority, new LinkedList<PreemptiveRequest>()); 51 RequestQueue[request.Priority].AddLast(request); 70 RequestQueue.Enqueue(request); 52 71 TriggerRequest(); 53 72 return request; … … 61 80 } 62 81 82 public virtual Event WhenAny() { 83 var whenAny = new Event(Environment); 84 WhenAnyQueue.Add(whenAny); 85 TriggerWhenAny(); 86 return whenAny; 87 } 88 89 public virtual Event WhenFull() { 90 var whenFull = new Event(Environment); 91 WhenFullQueue.Add(whenFull); 92 TriggerWhenFull(); 93 return whenFull; 94 } 95 96 public virtual Event WhenEmpty() { 97 var whenEmpty = new Event(Environment); 98 WhenEmptyQueue.Add(whenEmpty); 99 TriggerWhenEmpty(); 100 return whenEmpty; 101 } 102 103 public virtual Event WhenChange() { 104 var whenChange = new Event(Environment); 105 WhenChangeQueue.Add(whenChange); 106 return whenChange; 107 } 108 63 109 protected void DisposeCallback(Event @event) { 64 110 var request = @event as PreemptiveRequest; … … 69 115 if (Users.Count >= Capacity && request.Preempt) { 70 116 // Check if we can preempt another process 71 var oldest = Users.OfType<PreemptiveRequest>().Select((r, i) => new { Request = r, Index = i }) 72 .OrderByDescending(x => x.Request.Priority) 73 .ThenByDescending(x => x.Request.Time) 74 .ThenByDescending(x => x.Request.Preempt) 75 .ThenByDescending(x => x.Index) 76 .First().Request; 77 if (oldest.Priority > request.Priority || (oldest.Priority == request.Priority 78 && (!oldest.Preempt && request.Preempt || (oldest.Preempt == request.Preempt 79 && oldest.Time > request.Time)))) { 80 Users.Remove(oldest); 81 oldest.Process.Interrupt(new Preempted(request.Process, oldest.Time)); 117 // MaxItems are the least important according to priorty, time, and preemption flag 118 var preempt = Users.MaxItems(x => x).Last(); 119 if (preempt.CompareTo(request) > 0) { 120 preempt.IsPreempted = true; 121 Users.Remove(preempt); 122 preempt.Owner?.Interrupt(new Preempted(request.Owner, preempt.Time)); 82 123 } 83 124 } … … 89 130 90 131 protected virtual void DoRelease(Release release) { 91 if (!Users.Remove(release.Request)) { 92 var preemptRequest = release.Request as PreemptiveRequest; 93 if (preemptRequest != null) { 94 var current = RequestQueue[preemptRequest.Priority].First; 95 while (current != null && current.Value != release.Request) 96 current = current.Next; 97 if (current != null) RequestQueue[preemptRequest.Priority].Remove(current); 98 } 99 } 132 var req = (PreemptiveRequest)release.Request; 133 if (!Users.Remove(req) && !req.IsPreempted) 134 throw new InvalidOperationException("Released request does not have a user."); 100 135 release.Succeed(); 101 136 } 102 137 103 138 protected virtual void TriggerRequest(Event @event = null) { 104 foreach (var entry in RequestQueue) { 105 var requests = entry.Value; 106 var current = requests.First; 107 while (current != null) { 108 var request = current.Value; 109 DoRequest(request); 110 if (request.IsTriggered) { 111 var next = current.Next; 112 requests.Remove(current); 113 current = next; 114 } else current = current.Next; 115 } 139 while (RequestQueue.Count > 0) { 140 var request = RequestQueue.First; 141 DoRequest(request); 142 if (request.IsTriggered) { 143 RequestQueue.Dequeue(); 144 TriggerWhenEmpty(); 145 TriggerWhenChange(); 146 } else break; 116 147 } 117 148 } … … 120 151 while (ReleaseQueue.Count > 0) { 121 152 var release = ReleaseQueue.Peek(); 122 DoRelease(release); 123 if (release.IsTriggered) { 153 if (release.Request.IsAlive) { 154 if (!RequestQueue.TryRemove((PreemptiveRequest)release.Request)) 155 throw new InvalidOperationException("Failed to cancel a request."); 156 release.Succeed(); 124 157 ReleaseQueue.Dequeue(); 125 } else break; 126 } 158 } else { 159 DoRelease(release); 160 if (release.IsTriggered) { 161 ReleaseQueue.Dequeue(); 162 TriggerWhenAny(); 163 TriggerWhenFull(); 164 TriggerWhenChange(); 165 } else break; 166 } 167 } 168 } 169 170 protected virtual void TriggerWhenAny() { 171 if (Remaining > 0) { 172 if (WhenAnyQueue.Count == 0) return; 173 foreach (var evt in WhenAnyQueue) 174 evt.Succeed(); 175 WhenAnyQueue.Clear(); 176 } 177 } 178 179 protected virtual void TriggerWhenFull() { 180 if (InUse == 0) { 181 if (WhenFullQueue.Count == 0) return; 182 foreach (var evt in WhenFullQueue) 183 evt.Succeed(); 184 WhenFullQueue.Clear(); 185 } 186 } 187 188 protected virtual void TriggerWhenEmpty() { 189 if (Remaining == 0) { 190 if (WhenEmptyQueue.Count == 0) return; 191 foreach (var evt in WhenEmptyQueue) 192 evt.Succeed(); 193 WhenEmptyQueue.Clear(); 194 } 195 } 196 197 protected virtual void TriggerWhenChange() { 198 if (WhenChangeQueue.Count == 0) return; 199 foreach (var evt in WhenChangeQueue) 200 evt.Succeed(); 201 WhenChangeQueue.Clear(); 127 202 } 128 203 }
Note: See TracChangeset
for help on using the changeset viewer.