![]() |
User Manual, Developers Guide and API Documentation |
![]() |
virtual.
doStartup()
The openwns application will call this method to indicate
that construction of the environment has finished.
You will put your initialization code into it
and trigger one or more discrete events for the future.
In this example we simply call oue own function generateNewJob()
doShutdown()
The openwns application will call this method to indicate
that the simulation ends and the model should shut down.
There is currently no need to fill code in here.
doToString()
IOutputStreamable implements the stream output operator for us
It will get the contents to output to the stream by calling this method.
generateNewJob():
Here we count the number of jobs generated,
determine the interarrival time until the next job will arrive
and schedule an event for exactly this time in the future
using the discrete event scheduler function scheduleDelay()
If this is a new job and there is no other job in the system
the function processNextJob() is called.
processNextJob():
Called either from generateNewJob() if the queue was empty
or immediately after the predecessor job was finished
Here the random number for the processing time is drawn
and an event at this time in the future is scheduled
to call the function onJobProcessed()
onJobProcessed():
Called by the discrete event scheduler.
Unless there are no more jobs in the queue
it starts processing another job.
The number of jobs in the system is decremented again.
MESSAGE_SINGLE(NORMAL, logger_, "Your output string here");Exponential class
wns::simulator::Time delayToNextJob = jobInterarrivalTime_();
wns::simulator::getEventScheduler()->scheduleDelay(
boost::bind(&SimpleMM1Step1::generateNewJob, this),
delayToNextJob);
This looks weird, but it only binds our function generateNewJob() to an event scheduled after delayToNextJob seconds.config.get<ReturnType>("parameterName")config.get<wns::simulator::Time>("meanJobInterArrivalTime")STATIC_FACTORY_REGISTER_WITH_CREATOR in the cpp filePyConfig/openwns/queuingsystem.pyself.nameInFactory = 'openwns.queuingsystem.SimpleMM1Step1'openwns.setSimulator(sim) sets the configuration for this simulation
( 0.0000000) [ WNS] Application Start up modules
( 0.0000000) [ WNS] Application Creating simulation model: openwns.queuingsystem.SimpleMM1Step1
( 0.0000000) [ WNS] Application Startup simulation model: openwns.queuingsystem.SimpleMM1Step1
( 0.0000000) [ WNS] SimpleMM1Step1 MM1Step1 started, generating first job
Jobs in system: 0
( 0.0000000) [ WNS] SimpleMM1Step1 Generated new job, next job in 0.168591s
Jobs in system: 1
( 0.0000000) [ WNS] SimpleMM1Step1 Processing next job, processing time: 0.0144122s
Jobs in system: 1
( 0.0000000) [ WNS] Application Start Scheduler
( 0.0144122) [ WNS] SimpleMM1Step1 Finished a job
Jobs in system: 0
( 0.1685907) [ WNS] SimpleMM1Step1 Generated new job, next job in 0.236225s
Jobs in system: 1
( 0.1685907) [ WNS] SimpleMM1Step1 Processing next job, processing time: 0.178384s
Jobs in system: 1
...
( 10.0000000) [ WNS] Application Simulation finished
( 10.0000000) [ WNS] Application Calling shutDown for all modules
( 10.0000000) [ WNS] Application Destroying all modules
This is the contents of the file MM1Step1.hpp
#ifndef WNS_QUEUINGSYSTEM_MM1STEP1_HPP #define WNS_QUEUINGSYSTEM_MM1STEP1_HPP #include <WNS/rng/RNGen.hpp> #include <WNS/simulator/ISimulator.hpp> #include <WNS/simulator/ISimulationModel.hpp> #include <WNS/logger/Logger.hpp> #include <WNS/IOutputStreamable.hpp> #include <WNS/pyconfig/View.hpp> #include <WNS/distribution/Distribution.hpp> #include <boost/bind.hpp> // In the OpenWNS we use nested namespaces // which reflect the directory tree // This file is in ./src/queuingsystem/ // so the convention is to use the same namespace: namespace wns { namespace queuingsystem { // Simulation model for queueing system tutorial (step 1). // // Here We implement our own simulation model. To allow the openwns // application to load our custom simulation model, we must inherit // from wns::simulator::ISimulationModel. // class SimpleMM1Step1 : public IOutputStreamable, public wns::simulator::ISimulationModel { public: // All simulation models must be constructible from a // wns::pyconfig::View. explicit SimpleMM1Step1(const wns::pyconfig::View& configuration); // ^ The Python class used in MM1Step1.py // is intentionally called the same. // The Python view parameter here gets the values set as member // in the constructor of the Python class. private: // Implementation of the ISimulationModel interface. // The openwns application will call this method to indicate // that construction of the environment (scheduler, random number // generator, etc.) has finished. // // We will place our own startup code here virtual void doStartup(); // Implementation of the ISimulationModel interface. // The openwns application will call this method to indicate // that the simulation ends and the model should shut down. // // We will place our own shutdown code here virtual void doShutdown(); // Implementation of the IOutputStreamable interface. // IOutputStreamable implements the stream output operator for // us. It will get the contents to output to the stream by // calling this method. virtual std::string doToString() const; // Generates a new job that enters the queuing system void generateNewJob(); // Excuted after a job has been processed void onJobProcessed(); // Starts processing of the next job if one is available void processNextJob(); // A random number generator object pointer. wns::distribution::Distribution* jobInterarrivalTime_; // A random number generator object that creates exponentially // distributed random numbers. wns::distribution::Distribution* jobProcessingTime_; // Counter for the number of jobs in our system int jobsInSystem_; // Used to access the logging subsystem wns::logger::Logger logger_; }; } } #endif // NOT defined WNS_QUEUINGSYSTEM_MM1STEP1_HPP
#include <WNS/queuingsystem/MM1Step1.hpp> using namespace wns::queuingsystem; STATIC_FACTORY_REGISTER_WITH_CREATOR( SimpleMM1Step1, wns::simulator::ISimulationModel, "openwns.queuingsystem.SimpleMM1Step1", wns::PyConfigViewCreator); SimpleMM1Step1::SimpleMM1Step1(const wns::pyconfig::View& config) : jobsInSystem_(0), logger_(config.get("logger")) { wns::pyconfig::View disConfig = config.get("jobInterArrivalTimeDistribution"); std::string disName = disConfig.get<std::string>("__plugin__"); jobInterarrivalTime_ = wns::distribution::DistributionFactory::creator(disName)->create(disConfig); disConfig = config.get("jobProcessingTimeDistribution"); disName = disConfig.get<std::string>("__plugin__"); jobProcessingTime_ = wns::distribution::DistributionFactory::creator(disName)->create(disConfig); } void SimpleMM1Step1::doStartup() { MESSAGE_SINGLE(NORMAL, logger_, "MM1Step1 started, generating first job\n" << *this); generateNewJob(); } void SimpleMM1Step1::doShutdown() { } void SimpleMM1Step1::generateNewJob() { ++jobsInSystem_; wns::simulator::Time delayToNextJob = (*jobInterarrivalTime_)(); MESSAGE_SINGLE(NORMAL, logger_, "Generated new job, next job in " << delayToNextJob << "s\n" << *this); // The job is the only job in the system. There is no job that is currently // being served -> the server is free and can process the next job if (jobsInSystem_ == 1) { processNextJob(); } wns::simulator::getEventScheduler()->scheduleDelay( boost::bind(&SimpleMM1Step1::generateNewJob, this), delayToNextJob); } void SimpleMM1Step1::onJobProcessed() { --jobsInSystem_; MESSAGE_SINGLE(NORMAL, logger_, "Finished a job\n" << *this); // if there are still jobs, serve them if (jobsInSystem_ > 0) { processNextJob(); } } void SimpleMM1Step1::processNextJob() { wns::simulator::Time processingTime = (*jobProcessingTime_)(); wns::simulator::getEventScheduler()->scheduleDelay( boost::bind(&SimpleMM1Step1::onJobProcessed, this), processingTime); MESSAGE_SINGLE(NORMAL, logger_, "Processing next job, processing time: " << processingTime << "s\n" << *this); } std::string SimpleMM1Step1::doToString() const { std::stringstream ss; ss << "Jobs in system: " << jobsInSystem_; return ss.str(); }
1.5.5