source: trunk/HeuristicLab.ExtLibs/HeuristicLab.SimSharp/3.0.11/SimSharp-3.0.11/Core/Resources/PreemptiveResource.cs @ 15972

Last change on this file since 15972 was 15972, checked in by abeham, 3 years ago

#2926: Replaced Sim# 3.0.9 with 3.0.11

File size: 4.9 KB
Line 
1#region License Information
2/* SimSharp - A .NET port of SimPy, discrete event simulation framework
3Copyright (C) 2016  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;
21using System.Linq;
22
23namespace SimSharp {
24  public class PreemptiveResource {
25
26    public int Capacity { get; protected set; }
27
28    public int InUse { get { return Users.Count; } }
29
30    public int Remaining { get { return Capacity - InUse; } }
31
32    protected Environment Environment { get; private set; }
33
34    protected SortedList<int, LinkedList<PreemptiveRequest>> RequestQueue { get; private set; }
35    protected Queue<Release> ReleaseQueue { get; private set; }
36    protected HashSet<Request> Users { get; private set; }
37
38    public PreemptiveResource(Environment environment, int capacity = 1) {
39      if (capacity <= 0) throw new ArgumentException("Capacity must be > 0.", "capacity");
40      Environment = environment;
41      Capacity = capacity;
42      RequestQueue = new SortedList<int, LinkedList<PreemptiveRequest>>();
43      ReleaseQueue = new Queue<Release>();
44      Users = new HashSet<Request>();
45    }
46
47    public virtual PreemptiveRequest Request(int priority = 1, bool preempt = false) {
48      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);
52      TriggerRequest();
53      return request;
54    }
55
56    public virtual Release Release(PreemptiveRequest request) {
57      var release = new Release(Environment, request, TriggerRequest);
58      ReleaseQueue.Enqueue(release);
59      TriggerRelease();
60      return release;
61    }
62
63    protected void DisposeCallback(Event @event) {
64      var request = @event as PreemptiveRequest;
65      if (request != null) Release(request);
66    }
67
68    protected virtual void DoRequest(PreemptiveRequest request) {
69      if (Users.Count >= Capacity && request.Preempt) {
70        // 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));
82        }
83      }
84      if (Users.Count < Capacity) {
85        Users.Add(request);
86        request.Succeed();
87      }
88    }
89
90    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      }
100      release.Succeed();
101    }
102
103    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        }
116      }
117    }
118
119    protected virtual void TriggerRelease(Event @event = null) {
120      while (ReleaseQueue.Count > 0) {
121        var release = ReleaseQueue.Peek();
122        DoRelease(release);
123        if (release.IsTriggered) {
124          ReleaseQueue.Dequeue();
125        } else break;
126      }
127    }
128  }
129}
Note: See TracBrowser for help on using the repository browser.