source: trunk/HeuristicLab.ExtLibs/HeuristicLab.SimSharp/3.1.1/SimSharp-3.1.1/Core/Resources/Resource.cs @ 16779

Last change on this file since 16779 was 16779, checked in by abeham, 11 months ago

#2975: Updated Sim# to 3.1.1

File size: 5.9 KB
Line 
1#region License Information
2/* SimSharp - A .NET port of SimPy, discrete event simulation framework
3Copyright (C) 2019  Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4
5This program is free software: you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
7the Free Software Foundation, either version 3 of the License, or
8(at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program.  If not, see <http://www.gnu.org/licenses/>.*/
17#endregion
18
19using System;
20using System.Collections.Generic;
21
22namespace SimSharp {
23  /// <summary>
24  /// A resource holds a fixed number of anonymous entities.
25  ///
26  /// Requests are processed in FIFO order.
27  /// Releases are processed in FIFO order (usually no simulation time passes for a Release).
28  /// </summary>
29  public class Resource {
30
31    public int Capacity { get; protected set; }
32
33    public int InUse { get { return Users.Count; } }
34
35    public int Remaining { get { return Capacity - InUse; } }
36
37    protected Simulation Environment { get; private set; }
38
39    protected LinkedList<Request> RequestQueue { get; private set; }
40    protected Queue<Release> ReleaseQueue { get; private set; }
41    protected HashSet<Request> Users { get; private set; }
42    protected List<Event> WhenAnyQueue { get; private set; }
43    protected List<Event> WhenFullQueue { get; private set; }
44    protected List<Event> WhenEmptyQueue { get; private set; }
45    protected List<Event> WhenChangeQueue { get; private set; }
46
47    public Resource(Simulation environment, int capacity = 1) {
48      if (capacity <= 0) throw new ArgumentException("Capacity must > 0.", "capacity");
49      Environment = environment;
50      Capacity = capacity;
51      RequestQueue = new LinkedList<Request>();
52      ReleaseQueue = new Queue<Release>();
53      Users = new HashSet<Request>();
54      WhenAnyQueue = new List<Event>();
55      WhenFullQueue = new List<Event>();
56      WhenEmptyQueue = new List<Event>();
57      WhenChangeQueue = new List<Event>();
58    }
59
60    public virtual Request Request() {
61      var request = new Request(Environment, TriggerRelease, DisposeCallback);
62      RequestQueue.AddLast(request);
63      TriggerRequest();
64      return request;
65    }
66
67    public virtual Release Release(Request request) {
68      var release = new Release(Environment, request, TriggerRequest);
69      ReleaseQueue.Enqueue(release);
70      TriggerRelease();
71      return release;
72    }
73
74    public virtual Event WhenAny() {
75      var whenAny = new Event(Environment);
76      WhenAnyQueue.Add(whenAny);
77      TriggerWhenAny();
78      return whenAny;
79    }
80
81    public virtual Event WhenFull() {
82      var whenFull = new Event(Environment);
83      WhenFullQueue.Add(whenFull);
84      TriggerWhenFull();
85      return whenFull;
86    }
87
88    public virtual Event WhenEmpty() {
89      var whenEmpty = new Event(Environment);
90      WhenEmptyQueue.Add(whenEmpty);
91      TriggerWhenEmpty();
92      return whenEmpty;
93    }
94
95    public virtual Event WhenChange() {
96      var whenChange = new Event(Environment);
97      WhenChangeQueue.Add(whenChange);
98      return whenChange;
99    }
100
101    protected virtual void DisposeCallback(Event @event) {
102      var request = @event as Request;
103      if (request != null) {
104        Release(request);
105      }
106    }
107
108    protected virtual void DoRequest(Request request) {
109      if (Users.Count < Capacity) {
110        Users.Add(request);
111        request.Succeed();
112      }
113    }
114
115    protected virtual void DoRelease(Release release) {
116      if (!Users.Remove(release.Request))
117        throw new InvalidOperationException("Released request does not have a user.");
118      release.Succeed();
119    }
120
121    protected virtual void TriggerRequest(Event @event = null) {
122      while (RequestQueue.Count > 0) {
123        var request = RequestQueue.First.Value;
124        DoRequest(request);
125        if (request.IsTriggered) {
126          RequestQueue.RemoveFirst();
127          TriggerWhenEmpty();
128          TriggerWhenChange();
129        } else break;
130      }
131    }
132
133    protected virtual void TriggerRelease(Event @event = null) {
134      while (ReleaseQueue.Count > 0) {
135        var release = ReleaseQueue.Peek();
136        if (release.Request.IsAlive) {
137          if (!RequestQueue.Remove(release.Request))
138            throw new InvalidOperationException("Failed to cancel a request.");
139          release.Succeed();
140          ReleaseQueue.Dequeue();
141        } else {
142          DoRelease(release);
143          if (release.IsTriggered) {
144            ReleaseQueue.Dequeue();
145            TriggerWhenAny();
146            TriggerWhenFull();
147            TriggerWhenChange();
148          } else break;
149        }
150      }
151    }
152
153    protected virtual void TriggerWhenAny() {
154      if (Remaining > 0) {
155        if (WhenAnyQueue.Count == 0) return;
156        foreach (var evt in WhenAnyQueue)
157          evt.Succeed();
158        WhenAnyQueue.Clear();
159      }
160    }
161
162    protected virtual void TriggerWhenFull() {
163      if (InUse == 0) {
164        if (WhenFullQueue.Count == 0) return;
165        foreach (var evt in WhenFullQueue)
166          evt.Succeed();
167        WhenFullQueue.Clear();
168      }
169    }
170
171    protected virtual void TriggerWhenEmpty() {
172      if (Remaining == 0) {
173        if (WhenEmptyQueue.Count == 0) return;
174        foreach (var evt in WhenEmptyQueue)
175          evt.Succeed();
176        WhenEmptyQueue.Clear();
177      }
178    }
179
180    protected virtual void TriggerWhenChange() {
181      if (WhenChangeQueue.Count == 0) return;
182      foreach (var evt in WhenChangeQueue)
183        evt.Succeed();
184      WhenChangeQueue.Clear();
185    }
186  }
187}
Note: See TracBrowser for help on using the repository browser.