Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Hello, I\'m supposed to write C++ code that creates. A Non-Preemptive Scheduler

ID: 3752293 • Letter: H

Question

Hello, I'm supposed to write C++ code that creates. A Non-Preemptive Schedulerthat implements a priority queue using the heap ADT and Manipulates an extensible array.

The application should track the following events which occur during each time slice and print these activities:

1. *** Cycle #: c *** at the beginning of each cycle.

2. If the ready queue is empty, the message The CPU is idle should be displayed.

3. Whenever a process is finished executing, the message Process # pid has just terminated should be displayed.

4. If a process is still executing, the message Process # pid is executing. should be displayed.

5. Whenever a new process is created the message Adding job with pid # x and priority p and length t. should be displayed.

6. If no new process is created during a cycle, the message No new job this cycle. should be displayed.

At the end of the simulation, your program should also display the average throughput, number of processes completed per CPU cycle. It should also display the average wait time per process. The wait time of a process is the number of cycles from its creation to when it begins executing. To run your simulation for 1000 time slices (cycles) where the probability that a new process is created during each cycle is 0.2, your program will be executed with these values as command line tokens. Be sure to seed the random number generator using time of day. Do so at the beginning of the main.

This is the source code given to start with:

Single Core Scheduler.cpp

***A application to simulate a non-preemptive scheduler for a single-core CPU

#include <iostream>

#include <fstream>

#include <string>

#include <cstdlib>

#include "Heap.h"

#include "Heap.cpp"

#include "PCB.h"

using namespace std;

/**

* Single-core processor with non-preemptive scheduling simulator

* @param argc the number of command line arguments

* @param argv an array of array of chanracters containing command line arguments

* argv[0] - this file name

* argv[1] - number of cyles to run the simulation

* argv[2] - the mode: -r or -R for random mode and -f or -F for file mode

* argv[3] - if the mode is random, this entry contains the probability that

* a process is created per cycle and if the simulator is running in

* file mode, this entry contains the name of the file containing the

* the simulated jobs. In file mode, each line of the input file is

* in this format:

* <process ID> <priority value> <cycle of process creation> <time required to execute>

* @return exit_status

*/

int main(int argc, char** argv)

{

   //implement this function

   return 0;

}


Heap.cpp

**** An implementation file for a max-heap

#include "Heap.h"

using namespace std;

template <typename E>

Heap<E>::Heap()

{

//implement this function

}

template <typename E>

Heap<E>::Heap(std::function<bool(E,E)> fn)

{

//implement this function

}

template <typename E>

bool Heap<E>::isEmpty() const

{

   // implement this function

}

template<typename E>

void Heap<E>::insert(E item)

{

//implement this function

}

template<typename E>

E Heap<E>::remove() throw (HeapException)

{

   // implement this function

}

template<typename E>

const E& Heap<E>::peek() const throw (HeapException)

{

   //implement this function

}

template<typename E>

int Heap<E>::size()const

{

   //implement this function

}

template<typename E>

void Heap<E>::swap(int place, int parent)

{

   //implement this function

}

template<typename E>

void Heap<E>::rebuild(int root, int eSize)

{

   //implement this function

}

Heap.h

**** Describes the basic operations of a max-heap

#include <string>

#include <iostream>

#include <stdexcept>

#include <iostream>

#include <vector>

#include <functional>

#ifndef HEAP_H

#define HEAP_H

using namespace std;

/**

* This class reports Heap exceptions.

*/

class HeapException

{

public:

   HeapException(const string& aMessage)

   {

message = aMessage;

   }

   string what() const

   {

return message;

   }

private:

   string message;

};

template <typename E>

class Heap

{

private:

   /**

* A complete tree stored in a vector representing this

* binary heap

*/

   vector<E> tree;

   /**

* A less than comparator lambda bi-predicate function; that is,

* it compares two elements of this heap when rebuilding it

*/

   std::function<bool(E,E)> cmp = nullptr;

   /**

* Swaps a parent and child elements of this heap at the specified indices

* @param place an index of the child element on this heap

* @param parent an index of the parent element on this heap

*/

   void swap(int place, int parent);

   /**

* Rebuilds the heap to ensure that the heap property of the tree is preserved.

* @param root the root index of the sub-tree to be rebuilt

* @param eSize the size of this tree

*/

   void rebuild(int root, int eSize);

public:

   /**

Constructs an empty heap;

   */

   Heap<E>();

   /**

* A parameterized constructor

* @param fn - a greater than comparator function

*/

   Heap<E>(std::function<bool(E,E)> fn);

   /**

Determine whether the heap is empty.

@return true if the heap is empty;

otherwise, it returns false if the tree contains at least one item.

   */

   bool isEmpty() const;

   /**

Inserts an item into the heap.

@param item the value to be inserted.

@return none

   */

   void insert(E item);

   /**

An exception is generated if this method is invoked

by an empty heap. The maximum/minimum value is removed

from the heap if the heap is not empty and its effective

size is reduced by 1.

@return the maximum (in the case of a maxheap) or the

minimum (in the case of a minheap) on the heap.

   */

   E remove() throw (HeapException);

   /**

An exception is generated if this method is invoked

by an empty heap

@return the maximum (in the case of a maxheap) or the

minimum (in the case of a minheap) on the heap.

   */

   const E& peek() const throw (HeapException);

  

   /**

@return the size of the heap; the effective size of the

heap.

   */

   int size() const;

};

//HEAP_H

#endif

PCB.h

**** Models a process control block.

#include <string>

#include <iostream>

  

using namespace std;

class PCB

{

private:

/**

   * the process ID

   */

int pid;

/**

   * the priority value of this process

   */

int priority;

/**

   * running status

   */

int running;

/**

   * cycle during which this process was created

   */

int arrived;

/**

   * length of time this process will take to execute

   */

int length;

/**

   * cycle during which this process begins executing

   */

int start;

/**

   * how long the process waits before it begins executing

   */

int wait;    

public:

   /**

* Creates a simulated job with default values for its parameters.

*/

   PCB()

   {

priority = 20;

running = 0;

arrived = 0;

length = 0;

   }

   /**

* Creates a simulated job with the specified parameters.

* @param iD the process id

* @param pVal the priority value

* @param run the running status

* @param arr the arrival time

* @param len the number of cycles this process takes to execute

*/

   PCB(int iD, int pVal, int run, int arr, int len)

   {

pid = iD;

priority = pVal;

running = run;

arrived = arr;

length = len;

   }

   /**

* Gives the ID of this job.

* @return the process ID

*/

   int getPid() const

   {

return pid;

   }

  

   /**

* Gives the priority value of this process.

* @return the priority value of this process

*/

   int getPriority() const

   {

return priority;

   }

  

   /**

* Indicates whether this process is executing..

* @return the execution status of this process

*/

   bool isExecuting() const

   {

return running == 1;

   }

  

   /**

* Sets the running status of this job.

*/

   void execute()

   {

running = 1;

   }

   /**

* Gives the cycle during which this process was creates

* @return the cycle during which this process was created.

*/

   int getArrival() const

   {

return arrived;

   }

  

   /**

* Gives the number of cycles required to execute this process.

* @return the number of cycles required to execute this process

*/

   int getLength() const

   {

return length;

   }

  

   /**

* Gives the cycle during which this process began executing.

* @return the cycle during which this process began executing

*/

   int getStart() const

   {

return start;

   }

   /**

* Sets the cycle during which the process begins executing.

* @param startCycle the cycle during which this process begins executing.

*/

   void setStart(int startCycle)

   {

start = startCycle;

   }

  

   /**

* Gives the number of cycles this process waited before executing.

* @return the number of cycles from the process creation to its execution

*/

   int getWait() const

   {

return wait;

   }

   /**

* Sets the wait time for this process

* @param waitTime the number of cycles that this process waited

*/

   void setWait(int waitTime)

   {

wait = waitTime;

   }

   /**

* Determines whether two process control blocks are equal.

* @param pcb1 a simulated process control block

   * @param pcb2 a simulated process control block  

   * @return true when the specified process control blocks

   * are equal; otherwise, false.

   */

   friend bool operator==(const PCB& pcb1, const PCB& pcb2);

   /**

* Determines whether two process control blocks are not equal.

* @param pcb1 a simulated process control block

   * @param pcb2 a simulated process control block  

   * @return true when the specified process control blocks

   * are not equal; otherwise, false.

   */

   friend bool operator!=(const PCB& pcb1, const PCB& pcb2);

   /**

* Determines whether the first process control block will

   * execute after the second.

* @param pcb1 a simulated process control block

   * @param pcb2 a simulated process control block  

   * @return true when the first process control blocks

   * will be executed after the second; otherwise, false.

   */

   friend bool operator>(const PCB& pcb1, const PCB& pcb2);

   /**

* Determines whether the first process control block will

   * execute before the second.

* @param pcb1 a simulated process control block

   * @param pcb2 a simulated process control block  

   * @return true when the first process control blocks

   * will be executed before the second; otherwise, false.

   */

   friend bool operator<(const PCB& pcb1, const PCB& pcb2);

   /**

* Determines whether the first process control block will

   * execute after the second or is the same as the second.

* @param pcb1 a simulated process control block

   * @param pcb2 a simulated process control block  

   * @return true when the first process control blocks

   * will be executed after the second or is identical to

   * the second; otherwise, false.

   */

   friend bool operator>=(const PCB& pcb1, const PCB& pcb2);

   /**

* Determines whether the first process control block will  

* execute before the second or is the same as the second.

* @param pcb1 a simulated process control block  

* @param pcb2 a simulated process control block      

* @return true when the first process control blocks   

* will be executed before the second or is identical to  

* the second; otherwise, false.  

*/

   friend bool operator<=(const PCB& pcb1, const PCB& pcb2);

};

bool operator==(const PCB& pcb1, const PCB& pcb2)

{

   return pcb1.priority == pcb2.priority;

}

bool operator!=(const PCB& pcb1, const PCB& pcb2)

{

   return !(pcb1 == pcb2);

}

bool operator>(const PCB& pcb1, const PCB& pcb2)

{

   if (pcb1.priority < pcb2.priority)

return true;

   return false;

}

bool operator<(const PCB& pcb1, const PCB& pcb2)

{

   return (pcb1 != pcb2) && !(pcb1 > pcb2);

}

bool operator<=(const PCB& pcb1, const PCB& pcb2)

{

   return (pcb1 > pcb2) || (pcb1 == pcb2);

}

bool operator>=(const PCB& pcb1, const PCB& pcb2)

{

   return (pcb1 > pcb2) || (pcb1 == pcb2);

}  

Explanation / Answer

#include <ncbi_pch.hpp>

#include <corelib/ncbimtx.hpp>

#include <corelib/ncbi_limits.hpp>

#include <util/scheduler.hpp>

#include <util/sync_queue.hpp>

#include <util/error_codes.hpp>

#define NCBI_USE_ERRCODE_X Util_Scheduler

BEGIN_NCBI_SCOPE

/// Class storing full information about scheduled event for task execution

class CScheduler_QueueEvent : public CObject

{

public:

/// Id of the series

TScheduler_SeriesID id;

/// Task itself

CIRef<IScheduler_Task> task;

/// Time when this event will be executed

CTime exec_time;

/// Period of repetitive execution of the task

CTimeSpan period;

/// How to run repetitive tasks including not repeating at all

/// @sa IScheduler::ERepeatPattern

enum ERepeatPattern

{

/// Execute tasks in the specified period of time after the *START*

/// of previous task's execution

eWithRate = IScheduler::eWithRate,

/// Execute tasks in the specified period of time after the *END*

/// of previous task's execution

eWithDelay = IScheduler::eWithDelay,

/// Execute the task only once

eNoRepeat

};

/// Repeating pattern of the task

ERepeatPattern repeat_pattern;

/// Check if this event matches given series id

bool IsMatch(TScheduler_SeriesID match_id) const

{

return this->id == match_id;

}

/// Check if this event matches given task

bool IsMatch(IScheduler_Task* match_task) const

{

return &*this->task == match_task;

}

/// Dummy function to support code templates and avoid duplication of code

bool IsMatch(bool dummy_val) const

{

return dummy_val;

}

// In the absence of the following constructor, new compilers (as required

// by the new C++ standard) may fill the object memory with zeros,

// erasing flags set by CObject::operator new (see CXX-1808)

CScheduler_QueueEvent() {}

};

/// Class for comparing references to CSchedQueueTask by its execution time

struct PScheduler_QueueEvent_Compare

{

bool operator() (const CRef<CScheduler_QueueEvent>& left,

const CRef<CScheduler_QueueEvent>& right)

{

return left->exec_time < right->exec_time;

}

};

/// Thread-safe implementation of IScheduler interface

class CScheduler_MT

: public CObject,

public IScheduler

{

public:

/// Schedule task for one-time execution

virtual

TScheduler_SeriesID AddTask(IScheduler_Task* task,

const CTime& exec_time);

/// Schedule task for repetitive execution

virtual

TScheduler_SeriesID AddRepetitiveTask(IScheduler_Task* task,

const CTime& start_time,

const CTimeSpan& period,

ERepeatPattern repeat_pattern);

/// Remove series from scheduler queue

virtual

void RemoveSeries(TScheduler_SeriesID series_id);

/// Remove task from scheduler queue

virtual

void RemoveTask(IScheduler_Task* task);

/// Unschedule all series waiting in scheduler queue

virtual

void RemoveAllSeries(void);

/// Get full scheduler series list

virtual

void GetScheduledSeries(vector<SScheduler_SeriesInfo>* series) const;

/// Add listener which will be notified about changing in time

/// of availability of next scheduled task

virtual

void RegisterListener(IScheduler_Listener* listener);

/// Remove scheduler listener

virtual

void UnregisterListener(IScheduler_Listener* listener);

/// Get next time point when scheduler will be ready to execute some task

/// If there are already tasks to execute then return current time.

virtual

CTime GetNextExecutionTime(void) const;

/// Check if there are tasks in scheduler queue (if it is not empty)

virtual

bool IsEmpty(void) const;

/// Check if there are tasks ready to execute

virtual

bool HasTasksToExecute(const CTime& now) const;

/// Get information about next task that is ready to execute

/// If there are no tasks to execute then return id = 0 and task = NULL

virtual

SScheduler_SeriesInfo GetNextTaskToExecute(const CTime& now);

/// Be aware that task was just finished its execution

virtual

void TaskExecuted(TScheduler_SeriesID series_id, const CTime& now);

/// Constructor

CScheduler_MT(void);

protected:

/// Destructor. To be called from CRef.

virtual ~CScheduler_MT(void);

private:

/// Prohibit copying and assigning

CScheduler_MT(const CScheduler_MT&);

CScheduler_MT& operator= (const CScheduler_MT&);

/// Schedule task execution

/// @param id

/// id of the scheduler series. if 0 then it is assigned automatically

/// @param task

/// Task to execute

/// @param exec_time

/// Time when task will be executed

/// @param num_repeats

/// Total number of task executions

/// @param period

/// Period between task executions

/// @param isDelay

/// Whether period is executed from the beginning oor from the ending

/// of the task execution

/// @param guard

/// Guard for the main mutex which will be released at the end of method

TScheduler_SeriesID x_AddQueueTask

(

TScheduler_SeriesID id,

IScheduler_Task* task,

const CTime& exec_time,

const CTimeSpan& period,

CScheduler_QueueEvent::ERepeatPattern repeat_pattern,

CMutexGuard* guard

);

/// Change next execution time when queue of scheduled tasks is changed.

/// Notify all listeners about change if needed.

/// @param guard

/// Guardian locking main scheduler mutex which must be unlocked before

/// notification of listeners. NB: after method execution mutex is not

/// locked anymore.

void x_SchedQueueChanged(CMutexGuard* guard);

/// Implementation of removing task from queue.

/// The task is searched by criteria given as a parameter. Parameter

/// can be of any type that is accepted by

/// CScheduler_QueueEvent::IsMatch().

///

/// @sa CScheduler_QueueEvent::IsMatch(), RemoveSeries(), RemoveTask()

template <class T>

void x_RemoveTaskImpl(T task);

/// Type of queue for information about scheduled tasks

typedef CSyncQueue_multiset<CRef<CScheduler_QueueEvent>,

PScheduler_QueueEvent_Compare> TSchedQueue;

/// Type of list of information about currently executing tasks

typedef deque< CRef<CScheduler_QueueEvent> > TExecList;

/// Type of list of all scheduler listeners

typedef vector<IScheduler_Listener*> TListenersList;

/// Queue of scheduled tasks

TSchedQueue m_ScheduledTasks;

/// List of executing tasks

TExecList m_ExecutingTasks;

/// Counter for generating task id

CAtomicCounter m_IDCounter;

/// Main mutex for protection of changes in scheduler

mutable CMutex m_MainMutex;

/// List of all scheduler listeners

TListenersList m_Listeners;

/// Time of execution of nearest task

CTime m_NextExecTime;

};

// Max time_t minus a couple days to avoid any possible problems related to

// conversions to local time etc.

static const time_t kInfinityTimeT = 0x7FFB0000;

CScheduler_MT::CScheduler_MT(void)

{

m_NextExecTime.SetTimeT(kInfinityTimeT);

m_IDCounter.Set(0);

}

CScheduler_MT::~CScheduler_MT(void)

{

}

TScheduler_SeriesID

CScheduler_MT::x_AddQueueTask

(

TScheduler_SeriesID id,

IScheduler_Task* task,

const CTime& exec_time,

const CTimeSpan& period,

CScheduler_QueueEvent::ERepeatPattern repeat_pattern,

CMutexGuard* guard

)

{

// Be sure that task is referenced and will be destroyed in case

// of any exception

CIRef<IScheduler_Task> task_ref(task);

CRef<CScheduler_QueueEvent> event_info(new CScheduler_QueueEvent());

if (id == 0) {

id = (TScheduler_SeriesID)m_IDCounter.Add(1);

}

event_info->id = id;

event_info->task = task;

event_info->exec_time = exec_time;

event_info->period = period;

event_info->repeat_pattern = repeat_pattern;

m_ScheduledTasks.push_back(event_info);

x_SchedQueueChanged(guard);

// Mutex unlocked!!!

return id;

}

void

CScheduler_MT::x_SchedQueueChanged(CMutexGuard* guard)

{

TListenersList listeners;

{{

// This part will be guarded by the mutex

CTime next_time;

if (m_ScheduledTasks.size() == 0) {

next_time.SetTimeT(kInfinityTimeT);

}

else {

next_time = (*m_ScheduledTasks.begin())->exec_time;

}

if (next_time != m_NextExecTime) {

m_NextExecTime = next_time;

listeners = m_Listeners;

}

guard->Release();

}}

NON_CONST_ITERATE(TListenersList, it, listeners) {

(*it)->OnNextExecutionTimeChange(this);

}

}

TScheduler_SeriesID

CScheduler_MT::AddTask(IScheduler_Task* task, const CTime& exec_time)

{

CMutexGuard guard(m_MainMutex);

return x_AddQueueTask(0, task, exec_time, CTimeSpan(),

CScheduler_QueueEvent::eNoRepeat, &guard);

}

TScheduler_SeriesID

CScheduler_MT::AddRepetitiveTask(IScheduler_Task* task,

const CTime& start_time,

const CTimeSpan& period,

ERepeatPattern repeat_pattern)

{

CMutexGuard guard(m_MainMutex);

return x_AddQueueTask(0, task, start_time, period,

CScheduler_QueueEvent::ERepeatPattern(repeat_pattern),

&guard);

}

template <class T>

inline void

CScheduler_MT::x_RemoveTaskImpl(T task)

{

CMutexGuard guard(m_MainMutex);

bool is_begin_removed = false;

for (TSchedQueue::iterator it = m_ScheduledTasks.begin();

it != m_ScheduledTasks.end(); )

{

if ((*it)->IsMatch(task)) {

if (it == m_ScheduledTasks.begin()) {

is_begin_removed = true;

}

it = m_ScheduledTasks.erase(it);

}

else {

++it;

}

}

ITERATE(TExecList, it, m_ExecutingTasks) {

if ((*it)->IsMatch(task)) {

it->GetNCPointer()->repeat_pattern = CScheduler_QueueEvent::eNoRepeat;

}

}

if (is_begin_removed) {

x_SchedQueueChanged(&guard);

// Mutex unlocked!!!

}

}

void

CScheduler_MT::RemoveSeries(TScheduler_SeriesID series_id)

{

x_RemoveTaskImpl(series_id);

}

void

CScheduler_MT::RemoveTask(IScheduler_Task* task)

{

x_RemoveTaskImpl(task);

}

void

CScheduler_MT::RemoveAllSeries(void)

{

x_RemoveTaskImpl(true);

}

void

CScheduler_MT::GetScheduledSeries(vector<SScheduler_SeriesInfo>* series) const

{

series->clear();

{{

CMutexGuard guard(m_MainMutex);

series->resize(m_ScheduledTasks.size());

size_t ind = 0;

ITERATE (TSchedQueue, it, m_ScheduledTasks) {

(*series)[ind].id = (*it)->id;

(*series)[ind].task = (*it)->task;

++ind;

}

ITERATE(TExecList, it, m_ExecutingTasks) {

if ((*it)->repeat_pattern != CScheduler_QueueEvent::eNoRepeat) {

series->resize(ind + 1);

(*series)[ind].id = (*it)->id;

(*series)[ind].task = (*it)->task;

++ind;

}

}

}}

}

void

CScheduler_MT::RegisterListener(IScheduler_Listener* listener)

{

CMutexGuard guard(m_MainMutex);

m_Listeners.push_back(listener);

}

void

CScheduler_MT::UnregisterListener(IScheduler_Listener* listener)

{

CMutexGuard guard(m_MainMutex);

TListenersList::iterator it = find(m_Listeners.begin(), m_Listeners.end(),

listener);

if (it != m_Listeners.end()) {

m_Listeners.erase(it);

}

}

CTime

CScheduler_MT::GetNextExecutionTime(void) const

{

CMutexGuard guard(m_MainMutex);

return m_NextExecTime;

}

bool

CScheduler_MT::IsEmpty(void) const

{

CMutexGuard guard(m_MainMutex);

bool result = m_ScheduledTasks.empty();

if (result) {

ITERATE(TExecList, it, m_ExecutingTasks) {

if ((*it)->repeat_pattern != CScheduler_QueueEvent::eNoRepeat)

{

result = false;

break;

}

}

}

return result;

}

bool

CScheduler_MT::HasTasksToExecute(const CTime& now) const

{

CMutexGuard guard(m_MainMutex);

return m_NextExecTime <= now;

}

SScheduler_SeriesInfo

CScheduler_MT::GetNextTaskToExecute(const CTime& now)

{

SScheduler_SeriesInfo res_info;

res_info.id = 0;

CRef<CScheduler_QueueEvent> event_info;

{{

CMutexGuard guard(m_MainMutex);

if (m_ScheduledTasks.size() == 0

|| (*m_ScheduledTasks.begin())->exec_time > now)

{

return res_info;

}

event_info = m_ScheduledTasks.front();

m_ScheduledTasks.pop_front();

m_ExecutingTasks.push_back(event_info);

res_info.id = event_info->id;

res_info.task = event_info->task;

if (event_info->repeat_pattern == CScheduler_QueueEvent::eWithRate) {

x_AddQueueTask(event_info->id,

event_info->task,

event_info->exec_time + event_info->period,

event_info->period,

event_info->repeat_pattern,

&guard);

// Mutex unlocked!!!

// x_SchedQueueChanged() is called inside x_AddQueueTask()

}

else {

// x_SchedQueueChanged() should be called anyway because we've changed

// the beginning of the queue

x_SchedQueueChanged(&guard);

// Mutex unlocked!!!

}

}}

return res_info;

}

void

CScheduler_MT::TaskExecuted(TScheduler_SeriesID series_id, const CTime& now)

{

CMutexGuard guard(m_MainMutex);

CRef<CScheduler_QueueEvent> event_info;

NON_CONST_ITERATE(TExecList, it, m_ExecutingTasks) {

if ((*it)->IsMatch(series_id)) {

event_info = *it;

m_ExecutingTasks.erase(it);

break;

}

}

if (event_info.IsNull()) {

return;

}

if (event_info->repeat_pattern == CScheduler_QueueEvent::eWithDelay) {

x_AddQueueTask(event_info->id,

event_info->task,

now + event_info->period,

event_info->period,

event_info->repeat_pattern,

&guard);

// Mutex unlocked!!!

}

}

CIRef<IScheduler>

IScheduler::Create(void)

{

return CIRef<IScheduler>(new CScheduler_MT());

}

/// Standalone thread to execute scheduled tasks - implementation

class CScheduler_ExecThread_Impl

: public IScheduler_Listener,

public CThread

{

public:

/// Constructor

/// @param scheduler

/// Scheduler which tasks will be executed

CScheduler_ExecThread_Impl(IScheduler* scheduler);

/// Callback from the scheduler -- about changes in the execution timeline

virtual void OnNextExecutionTimeChange(IScheduler*);

/// Stop executing the tasks, and finish the thread.

/// This method should be called to force executor to finish its work

/// and destroy. Without it destruction will be impossible.

void Stop(void);

protected:

/// Destructor, to be called from CRef

virtual ~CScheduler_ExecThread_Impl();

/// Main thread function

virtual void* Main(void);

private:

/// Prohibit copying and assignment

CScheduler_ExecThread_Impl(const CScheduler_ExecThread_Impl&);

CScheduler_ExecThread_Impl& operator= (const CScheduler_ExecThread_Impl&);

/// Scheduler controlled by the executor

CIRef<IScheduler> m_Scheduler;

/// Reference to self to avoid destruction earlier than needed

CRef<CScheduler_ExecThread_Impl> m_SelfRef;

/// Semaphore for handling idle waiting

CSemaphore m_WaitTrigger;

/// If the thread has been requested to stop

volatile bool m_Stopped;

};

CScheduler_ExecThread_Impl::CScheduler_ExecThread_Impl(IScheduler* scheduler)

: m_Scheduler(scheduler),

m_WaitTrigger(0, kMax_Int),

m_Stopped(false)

{

m_SelfRef = this;

m_Scheduler->RegisterListener(this);

Run(CThread::fRunDetached);

}

CScheduler_ExecThread_Impl::~CScheduler_ExecThread_Impl(void)

{}

void

CScheduler_ExecThread_Impl::OnNextExecutionTimeChange(IScheduler*)

{

m_WaitTrigger.Post();

}

void

CScheduler_ExecThread_Impl::Stop(void)

{

m_Stopped = true;

m_WaitTrigger.Post();

m_SelfRef = NULL;

}

void*

CScheduler_ExecThread_Impl::Main(void)

{

CTime cur_time(CTime::eCurrent);

while ( !m_Stopped ) {

CTimeSpan timeout = m_Scheduler->GetNextExecutionTime() - cur_time;

m_WaitTrigger.TryWait(CTimeout(timeout));

// If we are already stopped we will not do unnecessary work

if ( !m_Stopped ) {

cur_time.SetCurrent();

for (;;) {

SScheduler_SeriesInfo task_info =

m_Scheduler->GetNextTaskToExecute(cur_time);

if (task_info.task.IsNull())

break;

try {

task_info.task->Execute();

}

catch (exception& e) {

ERR_POST_X(1, "Exception in scheduler task execution: "

<< e.what());

}

if (m_Stopped)

break;

cur_time.SetCurrent();

m_Scheduler->TaskExecuted(task_info.id, cur_time);

}

}

}

return NULL;

}

CScheduler_ExecutionThread::CScheduler_ExecutionThread(IScheduler* scheduler)

: m_Impl(new CScheduler_ExecThread_Impl(scheduler))

{

}

CScheduler_ExecutionThread::~CScheduler_ExecutionThread(void)

{

m_Impl->Stop();

}

END_NCBI_SCOPE

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote