Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
04/12/19 13:45:11 (5 years ago)
Author:
abeham
Message:

#2975: Updated Sim# to 3.1.1

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  
    11#region License Information
    22/* SimSharp - A .NET port of SimPy, discrete event simulation framework
    3 Copyright (C) 2016  Heuristic and Evolutionary Algorithms Laboratory (HEAL)
     3Copyright (C) 2019  Heuristic and Evolutionary Algorithms Laboratory (HEAL)
    44
    55This program is free software: you can redistribute it and/or modify
     
    2222
    2323namespace 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>
    2437  public class PreemptiveResource {
    2538
     
    3043    public int Remaining { get { return Capacity - InUse; } }
    3144
    32     protected Environment Environment { get; private set; }
    33 
    34     protected SortedList<int, LinkedList<PreemptiveRequest>> RequestQueue { get; private set; }
     45    protected Simulation Environment { get; private set; }
     46
     47    protected SimplePriorityQueue<PreemptiveRequest> RequestQueue { get; private set; }
    3548    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) {
    3956      if (capacity <= 0) throw new ArgumentException("Capacity must be > 0.", "capacity");
    4057      Environment = environment;
    4158      Capacity = capacity;
    42       RequestQueue = new SortedList<int, LinkedList<PreemptiveRequest>>();
     59      RequestQueue = new SimplePriorityQueue<PreemptiveRequest>();
    4360      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) {
    4869      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);
    5271      TriggerRequest();
    5372      return request;
     
    6180    }
    6281
     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
    63109    protected void DisposeCallback(Event @event) {
    64110      var request = @event as PreemptiveRequest;
     
    69115      if (Users.Count >= Capacity && request.Preempt) {
    70116        // 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));
    82123        }
    83124      }
     
    89130
    90131    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.");
    100135      release.Succeed();
    101136    }
    102137
    103138    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;
    116147      }
    117148    }
     
    120151      while (ReleaseQueue.Count > 0) {
    121152        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();
    124157          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();
    127202    }
    128203  }
Note: See TracChangeset for help on using the changeset viewer.