C + + Event-driven bank queuing simulation _c language

Source: Internet
Author: User
Tags prev

Recently regained the C + +, just saw the "C + + implementation of Bank queuing service simulation", but no laboratory building members, see the specific implementation, is used as a practice.

Simulation is the bank's queuing system, all customers in the order of arrival in the same queue, when there is a service window idle, the team head of the customer acceptance of service, completed the next customer began to accept the service.

This implementation is event-driven and handles objects as events rather than customers:
There are 2 kinds of events: customer to event and customer leaving event.
There are 2 queues: Customer Queues and event queues.

The logic of the program is as follows:
1. Initialize event queue to fill customer arrival event;
2. Handle the head of the event queue (always the earliest event), if the "customer arrives incident", turn to handle "customer arrives the incident", if "the customer leaves an incident", turn to handle "the customer leaves an event";
3. Loop to 2 until the event queue is empty or exceeds the opening hours;
4. To conduct clean-up work.

Event handling

Main process

Always handle the head of an event queue-that is, the event that occurred first.

 void Manager::run () {While
 (_event_queue.size ()!= 0) {
  _current_event = _event_queue.front ();
  if (_current_event->occur_time >= _total_serve_time)//exceeding business time break
   ;
  if (_customer_queue.size () = = 0 && _event_queue.size () <= _service_num)//Generate new customer arrival event
  {
   Generate_ Arrived_event (_generate_arrived_time);
   _current_event = _event_queue.front ();//update Current event, deal it with order
  }

  if (_current_event-> Event_type = = eventtype::arrivied)//Handle Customer Arrival event
   customer_arrived ();
  else if (_current_event->event_type = eventtype::D eparture)//process customer Leave event
   customer_departure ();
 }
 

Generate Customer Arrival Events

There are 2 different ways:
(1) One-time generation of all customer arrival events
Set the number of customers arriving within a unit time, generate all arrival events within the bank's business hours, and handle these events until the event queue is empty or exceeds the bank's business hours.

 void Manager::generate_arrived_event (int& current_time) {//Generate customer arrival events within the unit time group, Current_time is shared
 event* event ;
 int customer_per_minute = Random::uniform (Random_per_minute);//number of randomly arrived units in a unit of time, at least 1 cases while
 (Customer_per_minute > 0) {
  event = new event (current_time);
  _event_queue.enqueue (event);
  --customer_per_minute;
 }
 ++current_time;
 }
 

 _generate_arrived_time = 0;
 while (_generate_arrived_time < _total_serve_time) {//_total_serve_time is the bank's total business hours
  Generate_arrived_event (_ generate_arrived_time);
 } 

(2) Batch generation customer arrival events
Generate a customer arrival event only when needed, because it takes a certain amount of time for the customer to accept the service, usually the 1th method generates an arrival event that cannot be fully processed after the bank business hours, resulting in a waste of time and space. The implementation of the batch build arrival event is based on the fact that if the customer queue is empty and the event queue is less than equal to the number of service windows, the remaining events will not allow the service window to be full and generate a customer waiting for service, and a new customer arrival event is required.
Initializing an event queue:

 _generate_arrived_time = 0;//is still in chronological order to generate a customer arrival event while
 (_generate_arrived_time < Init_arrivied_event_num) {// Select the appropriate value, so that the initial generation of customer arrival events slightly more than the number of service windows, to ensure that the service window is full and waiting for customers can
  generate_arrived_event (_generate_arrived_time);
 } 

To determine conditions and generate arrival events:

 if (_customer_queue.empty () && _event_queue.size () <= _service_num)
{
 Generate_arrived_event (_ Generate_arrived_time);
 _current_event = &_event_queue.top ();//update Current event, deal it and order
} 

Since the customer arrival event is still generated in chronological order from 0 to the end of business hours, it is guaranteed that the customer's arrival event will not be processed for the newly inserted 10 minutes after the customer who has handled the 98-minute departure event (which may be generated by the customer arriving at 5 minutes). is to initialize the event queue to select the appropriate init_arrivied_event_num meaning: always ensure that the length of the event queue is greater than the number of service windows, The time that the newly generated customer arrives at the event is earlier than the time when the customer leaves the event (in chronological order to generate a customer arrival event, which ensures that the newly generated customer arrives at an event that is not less than the customer arrival event that is already in the event queue). The time that the customer leaves the event is random, and if it is ahead of the newly generated customer to event handling, may be disorderly) can also be handled correctly.

Generate Customer Departure events

Customer Queue Head Customer accepts service and teams out, generates customer departure events into team event queues. The time when the customer left the event = current time + The length of time the customer received the service.

 void manager::generate_departure_event (int service_index, int current_time) {
 _services[service_index].serve_ Customer (*_customer_queue.front ());
 _services[service_index].set_busy ()//service window is set to "Busy"
 _services[service_index].set_service_start_time (Current_ time);//service start
 _customer_queue.dequeue ();

 int duration = _services[service_index].get_customer_duration ();
 event* event = new Event (Current_time + Duration, EventType::D eparture, Service_index);/Generate customer Leave event
 _event_ Queue.enqueue (event);
} 

Handling Customer Arrival Events

To handle the logic of "Customer Arrival Events":
1. Generate 1 customers, join the customer queue;
2. Team event queue;
3. If there is an idle service window, generate "Customer leave event".

Here's the code:

void Manager::customer_arrived () {
 int idle_service_num = Get_idle_service_index ()//Get Idle service window, return-1 description not found
 int current_time = _current_event->occur_time;
 customer* customer = new Customer (current_time);//Customer arrival time is the customer arrival time, the customer receives the service the time long random
 _customer_queue.enqueue ( Customer);
 _event_queue.dequeue ();
  
 if (Idle_service_num!=-1)
  generate_departure_event (Idle_service_num, current_time);
 

Handling Customer Departure Events

To handle the logic of the "Customer Leave event":
1. The Customer's service window is set to idle, statistics customer information;
2. Team event queue;
3. If the customer queue is not empty and there is an idle service window, generate "Customer departure event".

Here's the code:

 void Manager::customer_departure () {
 int current_time = _current_event->occur_time;
 int service_index = _current_event->service_index;//Customer Departure service Window

 _customer_stay_time + = Current_time-
     _ Services[service_index].get_customer_arrive_time ()//statistics on the time of the customer's stay in the bank
 ++_total_served_customer_num;// Number of customers receiving services plus 1
 _services[service_index].set_idle ();
 _event_queue.dequeue ();

 if (_customer_queue.size () > 0) {
  Service_index = Get_idle_service_index (); If a customer leaves, it is necessary to get 1 free service windows, Here gets the smallest number of service Windows
  generate_departure_event (Service_index, current_time);
 }
 

Clean-up work:
1. To look for customers who are still receiving services and to count their information;
2. Release the dynamically requested memory.

Here's the code:

 void Manager::end () {for
 (int i = 0; i < _service_num; i++) {
  if (!_services[i].is_idle ()) {//statistics for customers who are receiving services 
   int service_start_time = _services[i].get_service_start_time ();
   int arrive_time = _services[i].get_customer_arrive_time ();
   int duration = _services[i].get_customer_duration ();

   _customer_stay_time + + service_start_time + duration-arrive_time;
   ++_total_served_customer_num
  }
 }

 Frees the dynamically requested memory
 _customer_queue.clear ();
 _event_queue.clear ();
 Delete[] _services
} 

A description of the queue

A custom queue is used in the program, and the priority queues and queues in the STL can be used, as needed, for event queues and for customer queues.
The head of the priority queue is always the highest priority node, and the sooner the event is taken, the higher the event priority, so this is the smallest heap-the time that occurs the least (the earliest) is at the top of the heap. This involves comparing the event types by using STL greater<event> (requiring overloaded operator>) or custom function objects to compare 2 event objects:
(1) Overloaded operator> operator

 Declare priority queues that use greater<event> as comparison functions std::p riority_queue<event, Std::vector<event>, std::greater< Event>> _event_queue; Event_queue.h #ifndef bankqueue_event_queue_h #define BANKQUEUE_EVENT_QUEUE_H #include "random.h" enum class Eventtyp

E:int {arrivied, departure};
     Class Event {public:event (): Occur_time (Random::uniform (Random_parameter)), Event_type (eventtype::arrivied), Service_index ( -1), Next (nullptr) {} Event (int occur_time): Occur_time (Occur_time), Event_type (Eventtype::arrivie D), Service_index ( -1), Next (nullptr) {} Event (int occur_time, eventtype event_type, int service_index): OCC Ur_time (Occur_time), Event_type (Event_type), Service_index (Service_index), Next (nullptr) {} friend bool O perator< (const event& event1, const event& event2);/imitate STL implementation, all through ' < ' to complete the remaining comparison operator friend bool operator > (const event& event1, const event& EVENT2);//For ' greater<event> ' use Public:inT Occur_time;
 int service_index;
 EventType Event_type;
Event *next;

}; inline bool operator< (const event& event1, const event& event2) {return Event1.occur_time < Event2.occur_
Time } inline bool Operator> (const event& event1, const event& event2) {return Event2 < event1;//through ' < ' implementation ' & gt; ' 

 Features} #endif//bankqueue_event_queue_h

(2) A more intuitive and simple approach is to customize the function objects for comparison:

 Declare priority queues that use Eventcomp as comparison functions
std::p riority_queue<event, Std::vector<event>, eventcomp> _event_queue ; struct Eventcomp
{
 bool operator () (const event& LHS, const event& RHS) Const
 {return
  lhs.occur _time > Rhs.occur_time;//occur_time is public, if private, you need to provide interface
 }
}; 

You can switch the use of 2 types of queues in Test.h by Use_self_define_queue macros.

Sequence of event queues

Event queues require that the team head always occurs at the earliest event, and that the minimum heap is a very good choice, and can be easily implemented by the STL precedence queues described earlier. The custom queue uses brute force method, which is sorted when the event is queued. To ensure that queues are in ascending order, when there are more elements in the queue (such as hundreds of), efficiency is lower than using STL precedence queues, which is one of the reasons why the customer arrives in batches: prevents too many elements of the event queue.
Customer queues do not need to be sorted, so the way in which the event queues are queued is implemented in the form of template exceptions:
Template<>

void Queue<event>::enqueue (event* event) {

 Event *cur = _front, *prev = nullptr;

 while (cur!= nullptr) {
  if (Cur->occur_time < event->occur_time) {
   prev = cur;
   cur = cur->next;
  }
  else break
   ;
 }

 if (prev = = nullptr) {
  event->next = _front;
  _front = event;
  if (_rear = = nullptr)
   _rear = event;//_rear is useless to event queue
 }
 else {
  Event->next = prev-& Gt;next;
  Prev->next = event;
  if (prev = = _rear)
   _rear = event;
 }
 ++length;
} 

The complete code is here.

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.