Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.ExtLibs/HeuristicLab.SimSharp/3.3.1/SimSharp-3.3.1/Core/Resources/PreemptiveResource.cs @ 17487

Last change on this file since 17487 was 17487, checked in by abeham, 4 years ago

#3065: update Sim# to 3.3.1

File size: 7.5 KB
Line 
1#region License Information
2/*
3 * This file is part of SimSharp which is licensed under the MIT license.
4 * See the LICENSE file in the project root for more information.
5 */
6#endregion
7
8using System;
9using System.Collections.Generic;
10using System.Linq;
11
12namespace SimSharp {
13  /// <summary>
14  /// A PreemptiveResource is similar to a <see cref="PriorityResource"/>. However,
15  /// it may be possible to interrupt a lower-priority user and hand over the resource.
16  ///
17  /// PreemptiveResource holds a fixed amount of anonymous entities.
18  /// Requests are processed in this order: priority, time, preemption, and finally FIFO.
19  /// Releases are processed in FIFO order (usually no simulation time passes for a Release).
20  /// </summary>
21  /// <remarks>
22  /// Working with PreemptiveResource, a process holding a request must always call
23  /// <see cref="Process.HandleFault"/> after yielding an event and handle a potential
24  /// interruption.
25  /// </remarks>
26  public class PreemptiveResource {
27
28    public int Capacity { get; protected set; }
29
30    public int InUse { get { return Users.Count; } }
31
32    public int Remaining { get { return Capacity - InUse; } }
33
34    protected Simulation Environment { get; private set; }
35
36    protected SimplePriorityQueue<PreemptiveRequest> RequestQueue { get; private set; }
37    protected Queue<Release> ReleaseQueue { get; private set; }
38    protected HashSet<PreemptiveRequest> Users { get; private set; }
39    protected List<Event> WhenAnyQueue { get; private set; }
40    protected List<Event> WhenFullQueue { get; private set; }
41    protected List<Event> WhenEmptyQueue { get; private set; }
42    protected List<Event> WhenChangeQueue { get; private set; }
43
44    public ITimeSeriesMonitor Utilization { get; set; }
45    public ITimeSeriesMonitor WIP { get; set; }
46    public ITimeSeriesMonitor QueueLength { get; set; }
47    public ISampleMonitor LeadTime { get; set; }
48    public ISampleMonitor WaitingTime { get; set; }
49    public ISampleMonitor BreakOffTime { get; set; }
50    public ISampleMonitor InterruptTime { get; set; }
51
52    public PreemptiveResource(Simulation environment, int capacity = 1) {
53      if (capacity <= 0) throw new ArgumentException("Capacity must be > 0.", "capacity");
54      Environment = environment;
55      Capacity = capacity;
56      RequestQueue = new SimplePriorityQueue<PreemptiveRequest>();
57      ReleaseQueue = new Queue<Release>();
58      Users = new HashSet<PreemptiveRequest>();
59      WhenAnyQueue = new List<Event>();
60      WhenFullQueue = new List<Event>();
61      WhenEmptyQueue = new List<Event>();
62      WhenChangeQueue = new List<Event>();
63    }
64
65    public virtual PreemptiveRequest Request(double priority = 1, bool preempt = false) {
66      var request = new PreemptiveRequest(Environment, TriggerRelease, DisposeCallback, priority, preempt);
67      RequestQueue.Enqueue(request);
68      TriggerRequest();
69      return request;
70    }
71
72    public virtual Release Release(PreemptiveRequest request) {
73      var release = new Release(Environment, request, TriggerRequest);
74      ReleaseQueue.Enqueue(release);
75      TriggerRelease();
76      return release;
77    }
78
79    public virtual Event WhenAny() {
80      var whenAny = new Event(Environment);
81      WhenAnyQueue.Add(whenAny);
82      TriggerWhenAny();
83      return whenAny;
84    }
85
86    public virtual Event WhenFull() {
87      var whenFull = new Event(Environment);
88      WhenFullQueue.Add(whenFull);
89      TriggerWhenFull();
90      return whenFull;
91    }
92
93    public virtual Event WhenEmpty() {
94      var whenEmpty = new Event(Environment);
95      WhenEmptyQueue.Add(whenEmpty);
96      TriggerWhenEmpty();
97      return whenEmpty;
98    }
99
100    public virtual Event WhenChange() {
101      var whenChange = new Event(Environment);
102      WhenChangeQueue.Add(whenChange);
103      return whenChange;
104    }
105
106    protected void DisposeCallback(Event @event) {
107      var request = @event as PreemptiveRequest;
108      if (request != null) Release(request);
109    }
110
111    protected virtual void DoRequest(PreemptiveRequest request) {
112      if (Users.Count >= Capacity && request.Preempt) {
113        // Check if we can preempt another process
114        // MaxItems are the least important according to priorty, time, and preemption flag
115        var preempt = Users.MaxItems(x => x).Last();
116        if (preempt.CompareTo(request) > 0) {
117          InterruptTime?.Add(Environment.ToDouble(Environment.Now - request.Time));
118          preempt.IsPreempted = true;
119          Users.Remove(preempt);
120          preempt.Owner?.Interrupt(new Preempted(request.Owner, preempt.Time));
121        }
122      }
123      if (Users.Count < Capacity) {
124        WaitingTime?.Add(Environment.ToDouble(Environment.Now - request.Time));
125        Users.Add(request);
126        request.Succeed();
127      }
128    }
129
130    protected virtual void DoRelease(Release release) {
131      var req = (PreemptiveRequest)release.Request;
132      if (!Users.Remove(req) && !req.IsPreempted)
133        throw new InvalidOperationException("Released request does not have a user.");
134      LeadTime?.Add(Environment.ToDouble(Environment.Now - release.Request.Time));
135      release.Succeed();
136    }
137
138    protected virtual void TriggerRequest(Event @event = null) {
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;
147      }
148      Utilization?.UpdateTo(InUse / (double)Capacity);
149      WIP?.UpdateTo(InUse + RequestQueue.Count);
150      QueueLength?.UpdateTo(RequestQueue.Count);
151    }
152
153    protected virtual void TriggerRelease(Event @event = null) {
154      while (ReleaseQueue.Count > 0) {
155        var release = ReleaseQueue.Peek();
156        if (release.Request.IsAlive) {
157          if (!RequestQueue.TryRemove((PreemptiveRequest)release.Request))
158            throw new InvalidOperationException("Failed to cancel a request.");
159          BreakOffTime?.Add(Environment.ToDouble(Environment.Now - release.Request.Time));
160          release.Succeed();
161          ReleaseQueue.Dequeue();
162        } else {
163          DoRelease(release);
164          if (release.IsTriggered) {
165            ReleaseQueue.Dequeue();
166            TriggerWhenAny();
167            TriggerWhenFull();
168            TriggerWhenChange();
169          } else break;
170        }
171      }
172      Utilization?.UpdateTo(InUse / (double)Capacity);
173      WIP?.UpdateTo(InUse + RequestQueue.Count);
174      QueueLength?.UpdateTo(RequestQueue.Count);
175    }
176
177    protected virtual void TriggerWhenAny() {
178      if (Remaining > 0) {
179        if (WhenAnyQueue.Count == 0) return;
180        foreach (var evt in WhenAnyQueue)
181          evt.Succeed();
182        WhenAnyQueue.Clear();
183      }
184    }
185
186    protected virtual void TriggerWhenFull() {
187      if (InUse == 0) {
188        if (WhenFullQueue.Count == 0) return;
189        foreach (var evt in WhenFullQueue)
190          evt.Succeed();
191        WhenFullQueue.Clear();
192      }
193    }
194
195    protected virtual void TriggerWhenEmpty() {
196      if (Remaining == 0) {
197        if (WhenEmptyQueue.Count == 0) return;
198        foreach (var evt in WhenEmptyQueue)
199          evt.Succeed();
200        WhenEmptyQueue.Clear();
201      }
202    }
203
204    protected virtual void TriggerWhenChange() {
205      if (WhenChangeQueue.Count == 0) return;
206      foreach (var evt in WhenChangeQueue)
207        evt.Succeed();
208      WhenChangeQueue.Clear();
209    }
210  }
211}
Note: See TracBrowser for help on using the repository browser.