2

I have been trying to develop a simple event driven simulator and started here

http://stdcxx.apache.org/doc/stdlibug/11-3.html

When I was playing around with the example with some modifications, I came across a condition where when two events (arrival, departure) happen at the same time (say at time unit 5), then the simulator just pops whatever is in the top of the event queue as can be seen from the below code snippet.

void simulation::run () {

while (! eventQueue.empty ()) {

event * nextEvent = eventQueue.top ();
eventQueue.pop ();
time = nextEvent->time;
nextEvent->processEvent ();
delete nextEvent;
  }
}

If both event happens at the same time, how can I enforce the condition that always pop a certain event(arrival event first) before the departure event.

Any help is much appreciated.

user2532296
  • 828
  • 1
  • 10
  • 27
  • If you want reproducible simulations, "time" **is** the order of events. There's no such thing as two events happening at the same time. – n. m. could be an AI Mar 07 '16 at 16:33
  • ok, I accept your point. But still I have the question, what happens if two events have the same time ? Can we deterministically say which event is going to happen first? through the rest of the simulation. Thanks – user2532296 Mar 07 '16 at 16:49
  • If two events occur at the same time, it's a **bug**. It is not supposed to happen in a correctly functioning system. Just fix it. – n. m. could be an AI Mar 07 '16 at 17:01
  • Consider a case, where a number of packets are arriving into the system and departing from the system based on some random process. In such a case, the (n+1)th packet arrival event can have the same time as the nth packet departing event. So I am unable to accept that it is a bug. Systems can have such properties. And I believe event driven simulation can handle such cases. – user2532296 Mar 07 '16 at 17:17
  • I'm afraid I don't understand. In my book, simulation time is the event serial number, by definition. You construct it this way. – n. m. could be an AI Mar 07 '16 at 17:40
  • @user2532296 is correct, only a Real Time OS is required to be deterministic. – jiveturkey Mar 07 '16 at 18:01
  • @jnbbender we're talking about simulation, and you must be able to replay a simulation exactly, otherwise what's the point? – n. m. could be an AI Mar 07 '16 at 19:18
  • @n.m. The simulation is deterministic in behaviour. My original question was, is there a provision to pop a specific event in the case of a tiebreak situation. – user2532296 Mar 07 '16 at 19:38
  • Why add complexity? Don't allow tie breaks. Make all timestamps different. – n. m. could be an AI Mar 07 '16 at 19:43
  • 1
    Use priority_queue - ordered by 2 factors - from more important: 1) time 2) event type. That's it. – PiotrNycz Mar 15 '16 at 14:55
  • Thanks, can you give some details on how it can be implemented in the following piece of code. https://gist.github.com/gmahet/2634e67e51a44d709df9 – user2532296 Mar 15 '16 at 17:11
  • @n.m. It's not a bug; events are queued according to time in many domains and applications. Communication networks is a prime example. PiotrNycz is right, although I suggest ordering by 3 factors: (time, event_type, event_id), where event_id is a unique serial number to ensure the ordering is well defined. – Lorenz Forvang Sep 20 '17 at 18:12

1 Answers1

5

I assume that eventQueue has the type described here (because that's what's referenced from the link in your question). From there, you can read that top() ...

Returns a constant reference to the element in the queue with the highest priority

... and that pop() ...

Removes the item with the highest priority from the queue.

So, taking the code from your questions, the most obvious approach would be to take all events out of the queue that have the same time, and only then process them:

while (! eventQueue.empty ()) {
  event * ev = eventQueue.top (); // WHY do you have pointers here ?!?!?
  time = ev->time;
  some_container<event *> arrivals, departures;
  // Take out all events that happen "now" from the queue
  while (time == ev->time) {
    eventQueue->pop();
    if (ev->type == ARRIVAL) {
      arrivals.push_back(ev);
    } else {
      departures.push_back(ev);
    }
    ev = eventQueue->top();
  }
  // Process arrivals
  for (event * e : arrivals) {
    e->processEvent();
    delete e; // Again: WTF pointers? raw? NOT a good idea!
  }
  // Process departures
  for (event * e : departures) {
    e->processEvent();
    delete e;
  }
}

BUT...

... that's not an idiomatic way to handle this in C++. Containers (at least ordered ones) in C++ normally have a template parameter specifying the way the elements should be ordered. And so does the std::priority_queue:

namespace std {
  template <class T,
            class Container = vector<T>,
            class Compare = less<Container::value_type> >
  class priority_queue;
}

Thus, the better approach here is to establish a total order among all events using a custom compare function object:

// sigh ... pointers ... raw pointers ... just WHY???!?
template<typename Event>
struct less_event_ptr {
  std::less<time_type> time_compare; // time_type hopefully is self-describing ...
  bool operator()(Event * lhs, Event * rhs) const {
    if (time_compare(lhs->time, rhs>-time)) {
      return true;
    }
    if (time_compare(rhs->time, lhs->time)) {
      return false;
    }
    if (lhs->type == ARRIVAL && rhs->type == DEPARTURE) {
      return true;
    }
    return false;
  }
};

Note that for this to be a total order, you need to be sure that there won't be multiple arrivals (or departures) at the same time. If there will (possibly) such circumstances, then you should (if you want a deterministic simulation) find other properties (a name? source?) of the events to bring them in order.

Your eventQueue would then be declared like

std::priority_queue<event *, std::vector<event *>, less_event_ptr<event>> eventQueue;
Daniel Jour
  • 15,896
  • 2
  • 36
  • 63
  • Hello Daniel, thanks for your reply. For now I have to deal with multiple arrival/departure events that an happen at the same time. I am checking this and will get back to you soon. – user2532296 Mar 11 '16 at 14:30
  • Hello Daniel, I could understand the solution that you are giving. I tried to come up with a minimum, complete and verifiable example, so that I could try your answer and accept it. Here is a simple code snippet (https://gist.github.com/gmahet/2634e67e51a44d709df9) that replicates the issue I was mentioning. Can you help me integrate you code so that i can test it and accept your answer. Thanks – user2532296 Mar 15 '16 at 14:28