home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
vol_300
/
394_01
/
c_sim
< prev
next >
Wrap
Text File
|
1994-01-17
|
73KB
|
3,785 lines
/*C++SIM/
Department of Computing Science,
The University,
Newcastle upon Tyne,
UK.
Permission to use, copy, modify and distribute this program for
evaluation, teaching and/or research purposes only and without fee is
hereby granted, providing that this copyright and permission notice
appear on all copies and supporting documentation, and that similar
conditions are imposed on any individual or organization to whom the
program is distributed. The University of Newcastle upon Tyne makes no
representation about the suitability of this software for any purpose.
It is provided "as is" without express or implied warranty.
$Id: Copyright,v 1.1 1993/06/14 13:07:22 nmcl Exp $
tRandom.cc
TestSet.cc
Process.cc
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef ELEMENT_H_
#include "Element.h"
#endif
#ifndef SET_H_
#include "Set.h"
#endif
Element::Element ()
: value(0)
{
}
Element::Element (long x)
: value(x)
{
}
Element::~Element ()
{
}
boolean Element::Belongs (Set* toCheck) const
{
boolean found = false;
Element* temp = (Element*) toCheck->First();
while ((temp) && (!found))
{
if (temp->GetValue() == value)
found = true;
else
temp = (Element*) temp->Suc();
}
return found;
}
#ifdef NO_INLINES
# define ELEMENT_CC_
# include "Element.n"
# undef ELEMENT_CC_
#endif
t.
Process.cc
Process.cc
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
/*
* This is used to simply test the operation of the Head and Link classes.
*/
#ifndef ELEMENT_H_
#define ELEMENT_H_
#ifndef COMMON_H_
#include "common.h"
#endif
#ifndef LINK_H_
#include "Link.h"
#endif
class Set;
class Element : public Link
{
public:
Element ();
Element (long);
~Element ();
boolean Belongs (Set*) const;
long GetValue () const;
void SetValue (long);
private:
long value;
};
#include "Element.n"
#endif
$
TestSet.cc
Process.cc
Process.cc
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#if defined(NO_INLINES) && !defined(ELEMENT_CC_)
#else
#ifndef NO_INLINES
# define INLINEF inline
#else
# define INLINEF
#endif
INLINEF long Element::GetValue () const
{
return value;
}
INLINEF void Element::SetValue (long x)
{
value = x;
}
#ifdef INLINEF
# undef INLINEF
#endif
#endif
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef BREAKS_H_
#include "Breaks.h"
#endif
#ifndef MACHINE_H_
#include "Machine.h"
#endif
#ifndef QUEUE_H_
#include "Queue.h"
#endif
extern Machine* M;
extern Queue JobQ;
Breaks::Breaks ()
{
RepairTime = new UniformStream(1, 10);
OperativeTime = new UniformStream(20, 1000);
interrupted_service = false;
}
Breaks::~Breaks ()
{
delete RepairTime;
delete OperativeTime;
}
void Breaks::Body ()
{
for(;;)
{
Hold((*OperativeTime)());
M->Broken();
M->Cancel();
if(!JobQ.IsEmpty())
interrupted_service = true;
Hold((*RepairTime)());
M->Fixed();
if (interrupted_service)
M->ActivateAt(M->ServiceTime() + CurrentTime());
else
M->ActivateAt();
interrupted_service = false;
}
}
Process.cc
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef BREAKS_H_
#define BREAKS_H_
#ifndef RANDOM_H_
#include <Random.h>
#endif
#ifndef PROCESS_H_
#include <Process.h>
#endif
/* Waits for a time interval drawn from the OperativeTime. Then kills of the
* Machine and waits for a time interval drawn from the RepairTime before
* restarting the Machine.
*/
class Breaks : public Process
{
public:
Breaks ();
~Breaks ();
void Body ();
private:
UniformStream* RepairTime;
UniformStream* OperativeTime;
boolean interrupted_service;
};
#endif
errupted_service = true;
Hold((*RepairTime)());
M->Fixed();
if (interrupted_service)
M->ActivateAt(M->ServiceTime() + CurrentTime());
else
M->ActivateAt();
interrupted_service = false;
}
}
Process.cc
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#include <iostream.h>
#ifndef PROCESS_H_
#include <Process.h>
#endif
#ifndef JOB_H_
#include "Job.h"
#endif
#ifndef MACHINE_H_
#include "Machine.h"
#endif
#ifndef QUEUE_H_
#include "Queue.h"
#endif
extern Machine* M;
extern Queue JobQ;
extern long TotalJobs;
extern double TotalResponseTime;
extern Scheduler *sc;
Job::Job ()
{
boolean empty;
ResponseTime = 0;
ArrivalTime = sc->CurrentTime();
empty = JobQ.IsEmpty();
JobQ.Enqueue(this);
TotalJobs++;
if (empty && !M->Processing() && M->IsOperational())
M->Activate();
}
Job::~Job ()
{
ResponseTime = sc->CurrentTime() - ArrivalTime;
#ifdef DEBUG
cerr << "ArrivalTime is " << ArrivalTime << "\n";
cerr << "Time now is " << sc->CurrentTime() << "\n";
cerr << "ResponseTime is " << ResponseTime << "\n";
#endif
TotalResponseTime += ResponseTime;
}
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef JOB_H_
#define JOB_H_
/* Instances of this class represent the jobs which the Machine attempts
* to process.
* If the -DDEBUG option is added to the CFLAGS for the Makefile then useful
* debugging code will be produced.
*/
class Job
{
public:
Job ();
~Job ();
private:
double ArrivalTime;
double ResponseTime;
};
#endif
;
ResponseTime = 0;
ArrivalTime C++SIM/Examples/Machine.cc
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef MACHINE_H_
#include "Machine.h"
#endif
#ifndef JOB_H_
#include "Job.h"
#endif
#ifndef QUEUE_H_
#include "Queue.h"
#endif
extern long ProcessedJobs;
extern long JobsInQueue;
extern long CheckFreq;
extern double MachineActiveTime;
extern Queue JobQ;
Machine::Machine (double mean)
{
STime = new ExponentialStream(mean);
operational = true;
working = false;
}
Machine::~Machine () { delete STime; }
void Machine::Body ()
{
double ActiveStart, ActiveEnd;
for (;;)
{
working = true;
while (!JobQ.IsEmpty())
{
ActiveStart = CurrentTime();
CheckFreq++;
JobsInQueue += JobQ.QueueSize();
Job* J = JobQ.Dequeue();
Hold((*STime)());
ActiveEnd = CurrentTime();
MachineActiveTime += ActiveEnd - ActiveStart;
ProcessedJobs++;
delete J;
}
working = false;
Cancel();
set_evtime(CurrentTime());
}
}
boolean Machine::Processing () { return working; }
void Machine::Broken () { operational = false; }
void Machine::Fixed ()
{
operational = true;
set_evtime(CurrentTime());
}
boolean Machine::IsOperational () { return operational; }
double Machine::ServiceTime () { return (*STime)(); }
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef MACHINE_H_
#define MACHINE_H_
#ifndef RANDOM_H_
#include <Random.h>
#endif
#ifndef PROCESS_H_
#include <Process.h>
#endif
/* This is the machine which services job requests. It is prone to simulated
* failures caused by the Breaks process.
*/
class Machine : public Process
{
public:
Machine (double);
~Machine ();
void Body ();
void Broken ();
void Fixed ();
boolean IsOperational ();
boolean Processing ();
double ServiceTime ();
private:
ExponentialStream* STime;
boolean operational;
boolean working;
};
#endif
();
CheckFreq++;
JobsInQueue += JobQ.QueueSize();
Job* J = JobQ.Dequeue();
Hold((*STime)());
ActiveEnd = CurrentTime();
MachineActiveTime += ActiveEnd - ActiveStart;
ProcessedJobs++;
delete J;
}
working = false;
Cancel();
set_evtime(CurrentTime());
}
}
boolean Machine::ProceC++SIM/Examples/MachineShop.cc
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#include <iostream.h>
#ifndef PROCESS_H_
#include <Process.h>
#endif
#ifndef MACHINESHOP_H_
#include "MachineShop.h"
#endif
#ifndef ARRIVALS_H_
#include "Arrivals.h"
#endif
#ifndef MACHINE_H_
#include "Machine.h"
#endif
#ifndef JOB_H_
#include "Job.h"
#endif
#ifndef QUEUE_H_
#include "Queue.h"
#endif
#ifndef BREAKS_H_
#include "Breaks.h"
#endif
Scheduler* sc;
Machine* M;
Queue JobQ;
long TotalJobs = 0;
long ProcessedJobs = 0;
long JobsInQueue = 0;
long CheckFreq = 0;
double TotalResponseTime = 0;
double MachineActiveTime = 0;
MachineShop::MachineShop () {}
MachineShop::~MachineShop () {}
void MachineShop::Body ()
{
sc = new Scheduler();
Arrivals* A = new Arrivals(10);
M = new Machine(8);
Job* J = new Job;
#ifdef BREAKS
Breaks* B = new Breaks;
B->Activate();
#endif
A->Activate();
sc->Resume();
while (ProcessedJobs < 100000)
Hold(10000);
cerr << "Total number of jobs processed " << TotalJobs << "\n";
cerr << "Total response time of " << TotalResponseTime << "\n";
cerr << "Average response time = " << (TotalResponseTime / ProcessedJobs) << "\n";
cerr << "Probability that machine is busy = " << (MachineActiveTime / CurrentTime()) << "\n";
cerr << "Average number of jobs present = " << (JobsInQueue / CheckFreq) << "\n";
sc->Suspend();
A->Suspend();
#ifdef BREAKS
B->Suspend();
#endif
}
void MachineShop::Await ()
{
Resume();
Thread::Self()->Suspend();
}
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef MACHINESHOP_H_
#define MACHINESHOP_H_
#ifndef PROCESS_H_
#include <Process.h>
#endif
/* This class starts up all of the main processes involved in the simulation.
* If the -DBREAKS option is added to the CFLAGS for the Makefile then the
* Breaks process will be created to deactivate of the Machine process at
* suitable intervals. Otherwise it will not be created and the Machine will
* operate uninterrupted.
*/
class MachineShop : public Process
{
public:
MachineShop ();
~MachineShop ();
void Body ();
void Await ();
};
#endif
() {}
MachineShop::~MachineShop () {}
void MachineShop::Body ()
{
sc = new Scheduler();
Arrivals* A = new Arrivals(10);
M = new Machine(8);
Job* J = new Job;
#ifdef BREAKS
Breaks* B = new Breaks;
B->Activate();
#endif
A->Activate();
sc->Resume();
while (ProcessedJobs < 100000)
Hold(10000);
C++SIM/Examples/Main.cc
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#include <iostream.h>
#ifndef COMMON_H_
#include <common.h>
#endif
#ifndef PROCESS_H_
#include <Process.h>
#endif
#ifndef MACHINESHOP_H_
#include "MachineShop.h"
#endif
int main()
{
Thread_Type::Initialize(); // Initialize the threads package.
MachineShop m; // Start up the real main body of the simulation.
m.Await(); // Suspend main's thread (NOTE: this MUST be done by all applications.)
return 0;
}
*/
class MachineShop : public Process
{
public:
MachineShop ();
~MachineShop ();
void Body ();
void Await ();
};
#endif
() {}
MachineShop::~MachineShop () {}
void MachineShop::Body ()
{
sc = new Scheduler();
Arrivals* A = new Arrivals(10);
M = new Machine(8);
Job* J = new Job;
#ifdef BREAKS
Breaks* B = new Breaks;
B->Activate();
#endif
A->Activate();
sc->Resume();
while (ProcessedJobs < 100000)
Hold(10000);
C++SIM/Examples/Queue.cc
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef QUEUE_H_
#include "Queue.h"
#endif
Queue::Queue ()
{
head = 0;
length = 0;
}
Queue::~Queue () { delete head; }
boolean Queue::IsEmpty ()
{
if (head == 0)
return true;
else
return false;
}
long Queue::QueueSize () { return length; }
Job* Queue::Dequeue ()
{
if (IsEmpty())
return 0;
List* ptr = head;
head = head->next;
length--;
return ptr->work;
}
void Queue::Enqueue (Job* toadd)
{
List* ptr = head;
if (IsEmpty())
{
head = new List;
ptr = head;
}
else
{
while (ptr->next != 0)
ptr = ptr->next;
ptr->next = new List;
ptr = ptr->next;
}
ptr->next = 0;
ptr->work = toadd;
length++;
}
M = new Machine(8);
Job* J = new Job;
#ifdef BREAKS
Breaks* B = new Breaks;
B->Activate();
#endif
A->Activate();
sc->Resume();
while (ProcessedJobs < 100000)
Hold(10000);
C++SIM/Examples/Queue.h
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef QUEUE_H_
#define QUEUE_H_
#ifndef PROCESS_H_
#include <Process.h>
#endif
#ifndef JOB_H_
#include "Job.h"
#endif
/* This is the queue on which Jobs are placed before they are used. */
struct List
{
Job* work;
List* next;
};
class Queue
{
public:
Queue ();
~Queue ();
boolean IsEmpty ();
long QueueSize ();
Job *Dequeue ();
void Enqueue (Job*);
private:
List* head;
long length;
};
#endif
ist* ptr = head;
if (IsEmpty())
{
head = new List;
ptr = head;
}
else
{
while (ptr->next != 0)
ptr = ptr->next;
ptr->next = new List;
ptr = ptr->next;
}
ptr->next = 0;
ptr->work = toadd;
length++;
}
M = new Machine(8);
Job* J = new Job;
#ifdef BREAKS
Breaks* B = new Breaks;
B->Activate();
#endif
A->Activate();
sc->Resume();
while (ProcessedJobs < 100000)
Hold(10000);
C++SIM/Examples/README
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
This director contains an example of a simulation written using the simulation
package. The example is taken from the book by Isi Mitrani (Simulation
Techniques for Discrete Event Systems p22).
The simulation is of a service which attempts to execute as many requests for
jobs as possible. The job requests are queued until the service can deal with
them. However, the service is prone to failures, and so jobs started will be
delayed until the service has been reactivated.
The classes provided include:
Arrivals - This class controls the rate at which Jobs arrive at
the service (Machine)
Breaks - This class controls the availability of the Machine by
"killing" it and restarting it at intervals drawn from
a Uniform distribution.
Job - This class represents the jobs which the Machine must process.
Machine - This is the Machine on which the service resides. It obtains
jobs from the job queue for the service and then attempts to
execute them. The machine can fail and so the response time for
jobs is not guaranteed to be the same.
MachineShop - This is the main part of the simulation which starts the
various processes (Scheduler, Arrivals, Machine, Job)
involved. It also prints out statistics for the response time
for the jobs.
Queue - This represents the queue which Jobs are placed on prior to being
used by the Machine (service).
Main - This is the body of the program which initializes the threads package
prior to the simulation starting.
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef ARRIVALS_H_
#define ARRIVALS_H_
#ifndef PROCESS_H_
#include <Process.h>
#endif
#ifndef RANDOM_H_
#include <Random.h>
#endif
/* Controls the rate at which Jobs arrive at the Machine */
class Arrivals : public Process
{
public:
Arrivals (double);
~Arrivals ();
void Body ();
private:
ExponentialStream* InterArrivalTime;
};
#endif
ver, the service is prone to faiC++SIM/Examples/Arrivals.cc
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#include <iostream.h>
#ifndef ARRIVALS_H_
#include "Arrivals.h"
#endif
#ifndef JOB_H_
#include "Job.h"
#endif
Arrivals::Arrivals (double mean) { InterArrivalTime = new ExponentialStream(mean); }
Arrivals::~Arrivals () { delete InterArrivalTime; }
void Arrivals::Body ()
{
for(;;)
{
Hold((*InterArrivalTime)());
Job* work = new Job();
}
}
dif
ver, the service is prone to faiC++SIM/Examples/Makefile
CC = cc
C++ = CC3.0.1
CPP = /lib/cpp
LEX = lex
MDEP = /usr/local/Arjuna/bin/makedepend
STRIPDEPEND = /usr/local/Arjuna/bin/stripdepend
CFLAGS = -g
CPPFLAGS =
C++FLAGS = -g +w
LDFLAGS = -g
LEXFLAGS =
MDEPFLAGS =
LOCAL_CFLAGS =
LOCAL_CPPFLAGS = -I/usr/local/Arjuna/include -I.. -I.
LOCAL_C++FLAGS =
LOCAL_LDFLAGS = -L../ -lThreads \
-L/usr/lib -lm -llwp
LOCAL_MDEPFLAGS = -I/usr/local/include/CC
OBJECTS = Arrivals.o Breaks.o Job.o Queue.o Machine.o Main.o MachineShop.o
SOURCES = Arrivals.cc Breaks.cc Job.cc Queue.cc Machine.cc Main.cc MachineShop.cc
HEADERS = Arrivals.h Breaks.h Job.h Queue.h Machine.h MachineShop.h
all: Main
Main: $(OBJECTS) $(HEADERS) ../libThreads.a
$(C++) -o Main $(OBJECTS) $(LDFLAGS) $(LOCAL_LDFLAGS)
Main.o: Main.cc
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) Main.cc
MachineShop.o: MachineShop.cc
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) MachineShop.cc
Arrivals.o: Arrivals.cc
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) Arrivals.cc
Breaks.o: Breaks.cc
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) Breaks.cc
Job.o: Job.cc Job.h
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) Job.cc
Queue.o: Queue.cc Queue.h
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) Queue.cc
Machine.o: Machine.cc Machine.h
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) Machine.cc
clean:
rm -f *.o
vclean: clean
rm -f Main *~* *.bak
depend:
$(MDEP) $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(MDEPFLAGS) $(LOCAL_MDEPFLAGS) $(SOURCES)
# DO NOT DELETE THIS LINE -- make depend depends on it.
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
/*
* This class essentially defines the linked list manager used by the SIMSET
* class in SIMULA.
*/
#ifndef HEAD_H_
#include "Head.h"
#endif
#ifndef LINK_H_
#include "Link.h"
#endif
#include <iostream.h>
Head::Head ()
: first(0),
last(0)
{
}
Head::~Head () { Clear(); }
void Head::AddFirst (Link* element)
{
if (!element)
return;
if (!first)
{
if (element->inList)
element->Out();
first = element;
last = element;
element->inList = true;
}
else
{
first->Precede(element);
first = first->Pred();
}
}
void Head::AddLast (Link* element)
{
if (last)
{
element->Follow(last);
last = element;
}
else
{
if (element->inList)
element->Out();
element->inList = true;
first = element;
last = element;
}
}
long Head::Cardinal () const
{
long numberOfElements = 0;
Link *tempPtr = first;
while (tempPtr)
{
numberOfElements++;
tempPtr = tempPtr->Suc();
}
return numberOfElements;
}
void Head::Clear ()
{
Link *tempPtr = first, *marker = 0;
while (!tempPtr)
{
marker = tempPtr;
tempPtr = tempPtr->Suc();
delete marker;
}
}
#ifdef NO_INLINES
# define HEAD_CC_
# include "Head.n"
# undef HEAD_CC_
#endif
hineShop.cc
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) MachineShop.cc
Arrivals.o: Arrivals.cc
$(C++) -c $(CPPFLAGS) $C++SIM/Head.h
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
/*
* This class essentially defines the linked list manager used by the SIMSET
* class in SIMULA.
*/
#ifndef HEAD_H_
#define HEAD_H_
#ifndef COMMON_H_
#include "common.h"
#endif
class Link;
class Head
{
public:
Head ();
virtual ~Head ();
Link* First () const;
Link* Last () const;
void AddFirst (Link*);
void AddLast (Link*);
long Cardinal () const;
boolean Empty () const;
void Clear ();
private:
Link *first, *last;
};
#include "Head.n"
#endif
gnu_thread.h
Process.cc
# include "Head.n"
# undef HEAD_CC_
#endif
hineShop.cc
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) MachineShop.cc
Arrivals.o: Arrivals.cc
$(C++) -c $(CPPFLAGS) $C++SIM/Head.n
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#if defined(NO_INLINES) && !defined(HEAD_CC_)
#else
#ifndef NO_INLINES
# define INLINEF inline
#else
# define INLINEF
#endif
INLINEF Link* Head::First () const
{
return first;
}
INLINEF Link* Head::Last () const
{
return last;
}
INLINEF boolean Head::Empty () const
{
return (boolean) (Cardinal() == 0);
}
#ifdef INLINEF
# undef INLINEF
#endif
#endif
t.h
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
To create the thread library libThreads.a simply type make. If you do not
possess Sun's lwp package then you will have to create a new class along the
same lines as the lwp_thread class and link it into the library. Such a class
has been provided for the GNU threads package, which is also included.
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
/*
* This class defines the elements of the linked lists within SIMSET.
*/
#ifndef LINK_H_
#include "Link.h"
#endif
#ifndef HEAD_H_
#include "Head.h"
#endif
Link::Link ()
: prev(0),
next(0),
inList(false)
{
}
Link::~Link () { RemoveElement(); }
void Link::RemoveElement ()
{
if (prev)
prev->next = next;
if (next)
next->prev = prev;
inList = false;
}
Link* Link::Out ()
{
RemoveElement();
return this;
}
void Link::InTo (Head* list)
{
if (list)
{
list->AddLast(this);
return;
}
(void) Out();
}
void Link::Precede (Link* element)
{
if (!element)
(void) Out();
else
if (!element->inList)
(void) Out();
else
{
if (inList)
(void) Out();
element->addBefore(this);
}
}
void Link::Follow (Link* element)
{
if (!element)
(void) Out();
else
if (!element->inList)
(void) Out();
else
{
if (inList)
(void) Out();
element->addAfter(this);
}
}
void Link::addAfter (Link* toAdd)
{
toAdd->inList = true;
toAdd->prev = this;
if (!next)
next = toAdd;
else
{
next->prev = toAdd;
toAdd->next = next;
next = toAdd;
}
}
void Link::addBefore (Link* toAdd)
{
toAdd->inList = true;
toAdd->next = this;
if (!prev)
prev = toAdd;
else
{
prev->next = toAdd;
toAdd->prev = prev;
prev = toAdd;
}
}
void Link::Follow (Head* list)
{
if (list)
list->AddFirst(this);
}
#ifdef NO_INLINES
# define LINK_CC_
# include "Link.n"
# undef LINK_CC_
#endif
DELETE THIS LINE -- make depend depends on it.
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
/*
* This class defines the elements of the linked lists within SIMSET.
*/
#ifndef LINK_H_
#define LINK_H_
#ifndef COMMON_H_
#include "common.h"
#endif
class Head;
class Link
{
public:
virtual ~Link ();
Link* Suc () const;
Link* Pred () const;
Link* Out ();
void InTo (Head*);
void Precede (Link*);
void Precede (Head*);
void Follow (Link*);
void Follow (Head*);
boolean inList;
protected:
Link (); // can only derive from this class
private:
void RemoveElement ();
void addAfter (Link*);
void addBefore (Link*);
Link *prev, *next;
};
#include "Link.n"
#endif
#endif
class Head;
class Link
{
public:
virtual ~Link ();
Link* Suc () const;
Link* Pred () const;
Link* Out ();
void InTo (Head*);
void Precede (Link*);
void Precede (Head*);
void Follow (Link*);
C++SIM/Link.n
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#if defined(NO_INLINES) && !defined(LINK_CC_)
#else
#ifndef NO_INLINES
# define INLINEF inline
#else
# define INLINEF
#endif
INLINEF Link* Link::Pred () const
{
return prev;
}
INLINEF Link* Link::Suc () const
{
return next;
}
INLINEF void Link::Precede (Head* list)
{
this->InTo(list);
}
#ifdef INLINEF
# undef INLINEF
#endif
#endif
Makefile
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
/*
* Various useful definitions.
*/
#ifndef COMMON_H_
#define COMMON_H_
#include <iostream.h>
// Do not forget to change the Makefile accordingly for the right thread library!
// Can choose from LWP_Thread or GNU_Thread
#define Thread_Type LWP_Thread
// Can choose from LWPTHREAD or GNUTHREAD
#define LWPTHREAD
#ifndef true
typedef int boolean;
#define true 1
#define false 0
#endif
#endif
Process.cc
(void) Out();
else
if (!element->inList)
(void) Out();
else
{
if (inList)
(void) Out();
element->addBefore(this);
}
}
void Link::Follow (Link* element)
{
if (!element)
(void) Out();
else
if (!element->inList)
(void) Out();C++SIM/Process.h
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef PROCESS_H_
#define PROCESS_H_
#ifndef COMMON_H_
#include "common.h"
#endif
#ifdef GNUTHREAD
# ifndef GNU_THREAD_H_
# include "gnu_thread.h"
# endif
#else
# ifndef LWP_THREAD_H_
# include "lwp_thread.h"
# endif
#endif
/* This is the main class for the simulation package. All objects which are to possess
* independent threads of control but which are to be controlled by the simulation
* scheduler MUST be derived from the Process class. The Scheduler, which is also an
* object which possesses an independent thread and which exists within the simulation
* environment, is shown here, but is only derived from the Thread_Type class and not Process
* as it is the central controller for the simulation environment and as such runs independently
* of everything else.
* If debugging is turned on (-DDEBUG added to the CFLAGS for the Makefile) then the scheduler
* will print out the current simulation time and other information.
*
* Thread_Type is a means of "transparently" changing the thread base class implementation
* from (at present) lwp_thread to gnu_thread. This should be changed in the file common.h
* and the Makefile may need changing to include the right thread library.
*/
static double SimulatedTime = 0.0;
class Scheduler : public Thread_Type
{
public:
Scheduler ();
~Scheduler ();
void Body ();
double CurrentTime () const;
private:
double ReActivateTime;
Thread* mainthread;
};
class Process : public Thread_Type
{
public:
static const int Never;
virtual ~Process ();
double Time () const; // returns the simulated time at which the current process is active
static double CurrentTime (); // returns the current simulation time
// There are four ways to activate a process:
// 1) before another process,
// 2) after another process,
// 3) at a specified (simulated) time, or
// 4) after a specified (simulated) delay
void Activate ();
void ActivateBefore (Process &);
void ActivateAfter (Process &);
void ActivateAt (double AtTime = SimulatedTime, boolean prior = false);
void ActivateDelay (double AtTime = SimulatedTime, boolean prior = false);
// Similarly, there are four ways to reactivate
// Note that if a process is already scheduled, the reactivate
// will simply re-schedule the process.
void ReActivateBefore (Process &);
void ReActivateAfter (Process &);
void ReActivateAt (double AtTime = SimulatedTime, boolean prior = false);
void ReActivateDelay (double AtTime = SimulatedTime, boolean prior = false);
void ReActivate ();
void Cancel (); // cancels next burst of activity, process becomes idle
double evtime () const; // time at which process is scheduled to be active
void set_evtime (double); // set wakeuptime (used by Scheduler)
boolean idle (); // true if process is not currently scheduled to wake up
boolean terminated () const; // returns whether or not the object has been passivated
// The pure virtual function, Body, defines the code that executes in the process
virtual void Body () = 0;
protected:
Process ();
void Hold (double t);// suspend current process for simulated time t
void Passivate (); // suspend current process (i.e., make idle)
private:
double wakeuptime;
boolean Terminated;
};
#include "Process.n"
#endif // PROCESS_H
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef PROCESSCONS_H_
#include "ProcessCons.h"
#endif
ProcessCons::ProcessCons (Process &p, ProcessCons *n) { Proc = &p; Next = n; }
#ifdef NO_INLINES
# define PROCESSCONS_CC_
# include "ProcessCons.n"
# undef PROCESSCONS_CC_
#endif
Random.cc
TestSet.cc
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef PROCESSCONS_H_
#define PROCESSCONS_H_
#ifndef COMMON_H_
#include "common.h"
#endif
#ifndef PROCESS_H_
#include "Process.h"
#endif
class ProcessCons
{
public:
ProcessCons (Process &p, ProcessCons *n);
Process *car ();
ProcessCons *cdr ();
void SetfCdr (ProcessCons *n);
private:
Process *Proc;
ProcessCons *Next;
};
#include "ProcessCons.n"
#endif
<MC++SIM/ProcessCons.n
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#if defined(NO_INLINES) && !defined(PROCESSCONS_CC_)
#else
#ifndef NO_INLINES
# define INLINEF inline
#else
# define INLINEF
#endif
INLINEF Process *ProcessCons::car ()
{
return Proc;
}
INLINEF ProcessCons *ProcessCons::cdr ()
{
return Next;
}
INLINEF void ProcessCons::SetfCdr (ProcessCons *n)
{
Next = n;
}
#ifdef INLINEF
# undef INLINEF
#endif
#endif
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef PROCESSITERATOR_H_
#include "ProcessIterator.h"
#endif
ProcessIterator::ProcessIterator (ProcessList &L) { ptr = L.Head; }
Process *ProcessIterator::operator ()()
{
if (ptr)
{
ProcessCons *p = ptr;
ptr = ptr->cdr();
return p->car();
}
return 0;
}
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef PROCESSITERATOR_H_
#define PROCESSITERATOR_H_
#ifndef COMMON_H_
#include "common.h"
#endif
#ifndef PROCESS_H_
#include "Process.h"
#endif
#ifndef PROCESSLIST_H_
#include "ProcessList.h"
#endif
#ifndef PROCESSCONS_H_
#include "ProcessCons.h"
#endif
class ProcessIterator
{
public:
ProcessIterator (class ProcessList &L);
Process *operator ()();
private:
ProcessCons *ptr;
};
#endif
ion
* environment, is shown here, but is only derived from the Thread_Type class and not Process
* as it is the central controller for the simulation environment and as such runs independently
* of everything else.
* If debugging is turned on (-DDEBUG added to the CFLAGS for the Makefile) then the scheduler
* will print oC++SIM/README
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
D. McCue, M. Little Computing Laboratory
29 November 1991 University of Newcastle upon Tyne, NE1 7RU, England
This is version 1.0 of C++SIM, a set of c++ class definitions that mimic the
process-based simulation facilities of SIMULA and the SIMSET routines.
The co-routine facility of Simula is implemented by Sun threads.
Classes are provided for various random number distributions.
The following classes are defined:
Process - An abstract class that exports the major functions
of the Simula class, process. To use, derive your own
class from the class Process. The pure virtual function,
Body, is the "main" procedure of the class. Note that,
like Simula, a process is not scheduled to run when it is
created. It must be explicitly 'activated'.
ProcessList - A list class for processes that (by default) orders
the elements by event time.
ProcessIterator - An iterator class for ProcessList.
ProcessCons - Allows LISP-like list manipulation (car & cdr).
Random - A series of classes which provide various random number
streams.
Element & Head - These classes form the basis of the SIMSET utility.
thread - The basic thread class, which defines what operations other
threads packages must provide. This is essentially a template
which allows other thread packages to be used as long as they
provide at least the operations necessary for this class.
lwp_thread - This is the Sun threads class.
gnu_thread - This is the interface to Gnu's thread package.
If you find any bugs or make modifications (e.g., ports to other thread
packages) or port the package to other systems then please let me know
so I can keep the sources up-to-date for other users.
Note: if you are interested in using C++SIM with Gnu threads then get in
touch with me and I will let you know how to go about that.
Send to: M.C.Little@ac.uk.newcastle
er a specified (simulated) delay
void Activate ();
void ActivateBefore (Process &);
void ActivateAfter (Process &);
void ActivateAt (double AtTime = SimulatedTime, boolean prior = false);
void ActivateDelay (double AtTime = SimulatedTime, boolean prior = false);
// Similarly, there are four ways to reactivate
// Note that if a process is already scheduled, the reactivate
// will simply re-schedule the process.
void ReActivateBefore (Process &);
void ReActiC++SIM/ProcessList.cc
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef PROCESSLIST_H_
#include "ProcessList.h"
#endif
ProcessList::ProcessList () { Head = 0; }
void ProcessList::Insert (Process &p, boolean prior)
{
// If list is empty, insert at head
if (!Head)
{
Head = new ProcessCons(p, Head);
return;
}
// Try to insert before (if there is anything scheduled later)
ProcessIterator iter(*this);
for (Process *prev = 0, *q = iter(); q; prev = q, q = iter())
{
if (prior)
{
if (q->evtime() >= p.evtime())
{
(void) InsertBefore(p, *q);
return;
}
}
else
if (q->evtime() > p.evtime())
{
(void) InsertBefore(p, *q);
return;
}
}
// Got to insert at the end (currently pointed at by 'prev'
(void) InsertAfter(p, *prev);
}
boolean ProcessList::InsertBefore (Process &ToInsert, Process &Before)
{
for (ProcessCons *prev=0, *p=Head; p; prev=p, p=p->cdr())
if (p->car() == &Before) {
ProcessCons *newcons = new ProcessCons(ToInsert, p);
if (prev)
prev->SetfCdr(newcons);
else
Head = newcons;
return true;
}
return false;
}
boolean ProcessList::InsertAfter (Process &ToInsert, Process &After)
{
for (ProcessCons *p = Head; p; p = p->cdr())
if (p->car() == &After) {
ProcessCons *newcons = new ProcessCons(ToInsert, p->cdr());
p->SetfCdr(newcons);
return true;
}
return false;
}
Process *ProcessList::Remove (const Process *element)
{
Process *p = 0;
// Take care of boundary condition - empty list
if (!Head) return 0;
// Change unspecified element to "remove head of list" request
if (element == 0)
return(Remove(Head->car()));
for (ProcessCons *prev = 0, *ptr = Head; ptr; prev = ptr, ptr = ptr->cdr())
{
if (ptr->car() == element)
{
ProcessCons *oldcons = ptr;
// unlink the cons cell for the element we're removing
if (prev)
prev->SetfCdr(ptr->cdr());
else
Head = ptr->cdr();
// return the pointer to the process
p = ptr->car();
// flush the dead cons cell
delete oldcons;
}
}
return p;
}
oid ActivateAt (double AtTime = SimulatedTime, boolean prior = false);
void ActivateDelay (double AtTime = SimulatedTime, boolean prior = false);
// Similarly, there are four ways to reactivate
// Note that if a process is already scheduled, the reactivate
// will simply re-schedule the process.
void ReActivateBefore (Process &);
void ReActiC++SIM/Random.cc
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#include <iostream.h>
#include <math.h>
#ifndef RANDOM_H_
#include "Random.h"
#endif
RandomStream::RandomStream (long MGSeed, long LCGSeed)
{
// Clean up input parameters
if ((MGSeed&1) == 0) MGSeed--;
if (MGSeed<0) MGSeed = -MGSeed;
if (LCGSeed<0) LCGSeed = -LCGSeed;
// Initialise state
MSeed = MGSeed;
LSeed = LCGSeed;
for (int i=0; i< (sizeof(series)/sizeof(double)); i++)
series[i] = MGen();
}
double RandomStream::MGen ()
{
// A multiplicative generator, courtesy I. Mitrani 1992,
// private correspondence
// Y[i+1] = Y[i] * 5^5 mod 2^26
// period is 2^24, initial seed must be odd
const long int two2the26th = 67108864; // 2**26
MSeed = (MSeed * 25) % two2the26th;
MSeed = (MSeed * 25) % two2the26th;
MSeed = (MSeed * 5) % two2the26th;
return (double) MSeed / (double) two2the26th;
}
double RandomStream::Uniform ()
{
// A linear congruential generator based on the algorithm from
// "Algorithms", R. Sedgewick, Addison-Wesley, Reading MA, 1983.
// pp. 36-38.
const long m=100000000;
const long b=31415821;
const long m1=10000;
// Do the multiplication in pieces to avoid overflow
long p0 = LSeed%m1,
p1 = LSeed/m1,
q0 = b%m1,
q1 = b/m1;
LSeed = (((((p0*q1+p1*q0)%m1)*m1+p0*q0)%m) + 1) % m;
// The results of the LC generator are shuffled with
// the multiplicative generator as suggested by
// Maclaren and Marsaglia (See Knuth Vol2, Seminumerical Algorithms)
long choose = LSeed % (sizeof(series)/sizeof(double));
double result = series[choose];
series[choose] = MGen();
return result;
}
double RandomStream::Error ()
{
const long r=100;
const long N=100*r;
long i, f[r];
for (i=0; i<r; i++) f[i]=0;
for (i=0; i<N; i++) f[(int) (Uniform()*r)]++;
long t=0;
for (i=0; i<r; i++) t += f[i]*f[i];
double rt = (double) r*t;
double rtN = rt / (double) N - (double) N;
return 1.0 - (rtN / r);
}
UniformStream::UniformStream (double l, double h, int StreamSelect)
{
lo = l;
hi = h;
range = hi-lo;
for (int ss=0; ss<StreamSelect*1000; ss++) (void) Uniform();
}
double UniformStream::operator() ()
{
return lo+(range*Uniform());
}
Draw::Draw(double p, int StreamSelect) : s(0,1)
{
prob = p;
for (int ss=0; ss<StreamSelect*1000; ss++) (void) s();
}
boolean Draw::operator() ()
{
double x = s();
if (x >= prob)
return true;
else
return false;
}
ExponentialStream::ExponentialStream (double m, int StreamSelect)
{
Mean = m;
for (int ss=0; ss<StreamSelect*1000; ss++) (void) Uniform();
}
double ExponentialStream::operator() ()
{
return -Mean*log(Uniform());
}
ErlangStream::ErlangStream (double m, double s, int StreamSelect)
{
Mean = m;
StandardDeviation = s;
double z = Mean/StandardDeviation;
k = (long) (z*z);
for (int ss=0; ss<StreamSelect*1000; ss++) (void) Uniform();
}
double ErlangStream::operator() ()
{
double z=1.0;
for (int i=0; i<k; i++) z*=Uniform();
return -(Mean/k)*log(z);
}
HyperExponentialStream::HyperExponentialStream (double m, double s, int StreamSelect)
{
Mean = m;
StandardDeviation = s;
double cv,z;
cv=StandardDeviation/Mean;
z = cv*cv;
p = 0.5*(1.0-sqrt((z-1.0)/(z+1.0)));
for (int ss=0; ss<StreamSelect*1000; ss++) (void) Uniform();
}
double HyperExponentialStream::operator() ()
{
double z = (Uniform()>p) ? Mean/(1.0-p) : Mean/p;
return -0.5*z*log(Uniform());
}
NormalStream::NormalStream (double m, double s, int StreamSelect)
{
Mean = m;
StandardDeviation = s;
z = 0.0;
for (int ss=0; ss<StreamSelect*1000; ss++) (void) Uniform();
}
double NormalStream::operator() ()
{
// Use the polar method, due to Box, Muller and Marsaglia
// Taken from Seminumerical Algorithms, Knuth, Addison-Wesley, p.117
double X2;
if (z!=0.0) {
X2 = z;
z = 0.0;
} else {
double S, v1, v2;
do {
v1 = 2.0*Uniform()-1.0;
v2 = 2.0*Uniform()-1.0;
S = v1*v1 + v2*v2;
} while (S>=1.0);
S = sqrt((-2.0*log(S))/S);
X2 = v1*S;
z = v2*S;
}
return Mean + X2*StandardDeviation;
}
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef PROCESSLIST_H_
#define PROCESSLIST_H_
#ifndef COMMON_H_
#include "common.h"
#endif
#ifndef PROCESS_H_
#include "Process.h"
#endif
#ifndef PROCESSITERATOR_H_
#include "ProcessIterator.h"
#endif
#ifndef PROCESSCONS_H_
#include "ProcessCons.h"
#endif
class ProcessList
{
public:
ProcessList ();
void Insert (Process &, boolean prior=false);
boolean InsertBefore (Process &ToInsert, Process &Before);
boolean InsertAfter (Process &ToInsert, Process &After);
Process *Remove (const Process *p=0);
private:
friend class ProcessIterator;
ProcessCons *Head;
};
#endif
eriod is 2^24, initial seed must be odd
const long int two2the26th = 67108864; // 2**26
MSeed = (MSeed * 25) % two2the26th;
MSeed = (MSeed * 25) % two2the26th;
MSeed = (MSeed * 5) % two2the26th;
return (double) MSeed / (double) two2the26th;
}
double RandomStream::Uniform ()
{C++SIM/Set.cc
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef SET_H_
#include "Set.h"
#endif
#ifndef ELEMENT_H_
#include "Element.h"
#endif
#include <iostream.h>
Set::Set () {}
Set::~Set () {}
Set* Set::Intersect (Set* toCheck) const
{
Set* tempSet = new Set;
Element *E = 0;
if (!Empty() && !toCheck->Empty())
{
E = (Element*) First();
while (E)
{
if (E->Belongs(toCheck))
{
Element* toAdd = new Element(E->GetValue());
toAdd->InTo(tempSet);
}
E = (Element*) E->Suc();
}
}
return tempSet;
}
Process *p=0);
private:
friend class ProcessIterator;
ProcessCons *Head;
};
#endif
eriod is 2^24, initial seed must be odd
const long int two2the26th = 67108864; // 2**26
MSeed = (MSeed * 25) % two2the26th;
MSeed = (MSeed * 25) % two2the26th;
MSeed = (MSeed * 5) % two2the26th;
return (double) MSeed / (double) two2the26th;
}
double RandomStream::Uniform ()
{C++SIM/Random.h
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef RANDOM_H_
#define RANDOM_H_
#ifndef COMMON_H_
#include "common.h"
#endif
////////////////////////////////////////////////////////////////////////////////
// //
// This file contains the interfaces for five different (pseudo-) random //
// number generators: //
// //
// 1) Uniform - returns a number drawn from a uniform distribution //
// with the given lower and upper bounds. //
// Note: there are two versions of this class, one //
// returning integers and the other doubles //
// //
// 2) Exponential - returns a number from an exponential distribution //
// with the given mean //
// //
// 3) Erlang - returns a number from an Erlang distribution with //
// the given mean and standard deviation //
// //
// 4) HyperExponential - returns a number from a hyperexpontial distribution //
// with the given mean and standard deviation //
// //
// 5) Normal - returns a number from a normal distribution with //
// the given mean and standard deviation. //
// //
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// The class RandomStream is an abstract base class from which the other //
// distribution classes are derived. //
////////////////////////////////////////////////////////////////////////////////
class RandomStream
{
public:
RandomStream (long MGSeed=772531L, long LCGSeed=1878892440L);
virtual double operator() ()=0;
double Error (); // returns a chi-square error measure on the uniform
// distribution function
protected:
double Uniform ();
private:
double MGen ();
double series[128];
long MSeed, LSeed;
};
class UniformStream : public RandomStream
{
public:
UniformStream (double lo, double hi, int StreamSelect=0);
virtual double operator() ();
private:
double lo,hi;
double range;
};
class Draw
{
public:
Draw (double p, int StreamSelect=0);
virtual boolean operator() ();
private:
UniformStream s;
double prob;
};
class ExponentialStream : public RandomStream
{
public:
ExponentialStream (double Mean, int StreamSelect=0);
virtual double operator() ();
private:
double Mean;
};
class ErlangStream : public RandomStream
{
public:
ErlangStream (double Mean, double StandardDeviation, int StreamSelect=0);
virtual double operator() ();
private:
double Mean,StandardDeviation;
long k;
};
class HyperExponentialStream : public RandomStream
{
public:
HyperExponentialStream (double Mean, double StandardDeviation, int StreamSelect=0);
virtual double operator() ();
private:
double Mean,StandardDeviation;
double p;
};
class NormalStream : public RandomStream
{
public:
NormalStream (double Mean, double StandardDeviation, int StreamSelect=0);
virtual double operator() ();
private:
double Mean,StandardDeviation;
double z;
};
#endif // RANDOM_H
lgorithms, Knuth, Addison-Wesley, p.117
double X2;
if (z!=0.0) {
X2 = z;
z = 0.0;
} else {
double SC++SIM/Set.h
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
/*
* This is used to simply test the operation of the Head and Link classes.
*/
#ifndef SET_H_
#define SET_H_
#ifndef COMMON_H_
#include "common.h"
#endif
#ifndef HEAD_H_
#include "Head.h"
#endif
#ifndef LINK_H_
#include "Link.h"
#endif
class Set : public Head
{
public:
Set ();
~Set ();
Set* Intersect (Set*) const;
};
#endif
C++SIM/TestRandom.cc
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#include <stdlib.h> // to get getopt
#include <iostream.h>
#include "Random.h"
void Gen(int count, RandomStream *r, const char *title)
{
// Create and initialise buckets for a bar graph
int i;
int bucket[100];
for (i=0; i<100; i++) bucket[i]=0;
// generate numbers and update bucket counts
for (i=0; i<count; i++) {
double result = (*r)();
int idx = result < 0.0 ? 0 : (result > 100.0) ? 100 : (int) result;
bucket[idx]++;
}
// output a title followed by the bucket counts
cout << endl << '"' << title << '"' << endl;
for (i=0; i<100; i++)
cout << i << ".0 " << bucket[i] << endl;
cerr << "Chi-Square error measure: " << r->Error() << endl;
}
int main (int argc, char **argv)
{
extern char *optarg;
extern int optind;
int c;
int count=10000;
int errflg = 0;
int uniform=0, normal=0, exponential=0, hyperexponential=0, erlang=0;
int skip=0;
while ((c = getopt(argc, argv, "s:c:unxhe")) != -1)
switch(c) {
case 'c': count = atoi(optarg); break;
case 'u': uniform++; break;
case 'n': normal++; break;
case 'x': exponential++; break;
case 'h': hyperexponential++; break;
case 'e': erlang++; break;
case 's': skip = atoi(optarg); break;
case '?':
default: errflg++;
}
// ASSERT: argc-optind == number of arguments remaining
// argv[optind] == first non-flag argument
if (errflg || (argc-optind)) {
cerr << "usage: " << argv[0] << "[-c <number>][-u][-n][-x][-h][-e]" << endl;
cerr << "\t-c 99\t\tgenerate 99 points for each distribution" << endl;
cerr << "\t-u\t\toutput a data set for a uniform distribution" << endl;
cerr << "\t-n\t\toutput a data set for a normal distribution" << endl;
cerr << "\t-x\t\toutput a data set for an exponential distribution" << endl;
cerr << "\t-h\t\toutput a data set for a hyperexponential distribution" << endl;
cerr << "\t-e\t\toutput a data set for an erlang distribution" << endl;
return 2;
}
// output a normal distribution by default
if (!uniform && !normal && !exponential && !hyperexponential && !erlang)
normal++;
cout << "TitleText: Random Number Distributions"
<< " (" << count << " numbers/distribution)"
<< endl;
for (int q=0; q<skip; q++) delete new UniformStream(0.0, 100.0);
if (uniform) Gen (count, new UniformStream (0.0, 100.0), "Uniform");
if (normal) Gen (count, new NormalStream (50.0, 15.0), "Normal");
if (exponential) Gen (count, new ExponentialStream(50.0), "Exponential");
if (hyperexponential) Gen (count, new HyperExponentialStream(50.0, 55.0), "HyperExponential");
if (erlang) Gen (count, new ErlangStream(50.0, 15.0), "Erlang");
return 0;
}
};
class Draw
{
public:
Draw (double p, int StreamSelect=0);
virtual boolean operator() ();
private:
UniformStream s;
douC++SIM/TestSet.cc
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef SET_H_
#include "Set.h"
#endif
#ifndef ELEMENT_H_
#include "Element.h"
#endif
#include <iostream.h>
int main ()
{
Set S1, S2;
Set *S3 = 0;
Element* E = 0;
for (int i = 0; i < 10; i++)
{
E = new Element(i);
E->InTo(&S1);
}
for (int j = 8; j < 14; j++)
{
E = new Element(j);
E->InTo(&S2);
}
S3 = S1.Intersect(&S2);
E = (Element*) S3->First();
cout << "Intersection is:" << endl;
while (E)
{
cout << "value: " << E->GetValue() << endl;
E = (Element*) E->Suc();
}
return 0;
}
i++)
cout << i << ".0 " << bucket[i] << endl;
cerr << "Chi-Square error measure: " << r->Error() << endl;
}
int main (int argc, char **argv)
{
extern char *optarg;
extern int optind;
int c;
int count=10000;
int errflg = 0;
int uniform=0, normal=0, exponential=0, hyperexponential=0, erlang=0;
C++SIM/Makefile
CC = cc
C++ = CC3.0.1
CPP = /lib/cpp
LEX = lex
MDEP = /usr/local/Arjuna/bin/makedepend
STRIPDEPEND = /usr/local/Arjuna/bin/stripdepend
CFLAGS = -g
CPPFLAGS =
C++FLAGS = -g +w
LDFLAGS = -g
LEXFLAGS =
MDEPFLAGS =
LOCAL_CFLAGS =
LOCAL_CPPFLAGS =
LOCAL_C++FLAGS =
LOCAL_LDFLAGS = -L/usr/lib -lm -llwp
LOCAL_MDEPFLAGS = -I/usr/local/include/CC
LIB = libThreads.a
OBJECTS = Process.o ProcessIterator.o ProcessList.o ProcessCons.o \
Link.o Head.o Set.o Element.o \
thread.o lwp_thread.o Random.o
SOURCES = Process.cc ProcessIterator.cc ProcessList.cc ProcessCons.cc \
Link.cc Head.cc Set.cc Element.cc \
thread.cc lwp_thread.cc Random.cc
HEADERS = ProcessCons.h ProcessIterator.h ProcessList.h common.h \
Link.h Head.h Set.h Element.h \
thread.h lwp_thread.h Random.h
INLINES = Element.n Head.n Link.n Process.n ProcessCons.n
all: $(LIB)
Process.o: Process.cc Process.h Process.n
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) Process.cc
ProcessCons.o: ProcessCons.cc ProcessCons.h ProcessCons.n
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) ProcessCons.cc
ProcessIterator.o: ProcessIterator.cc ProcessIterator.h
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) ProcessIterator.cc
ProcessList.o: ProcessList.cc ProcessList.h
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) ProcessList.cc
Link.o: Link.cc Link.h Link.n
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) Link.cc
Head.o: Head.cc Head.h Head.n
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) Head.cc
Set.o: Set.cc Set.h
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) Set.cc
Element.o: Element.cc Element.h Element.n
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) Element.cc
Random.o: Random.cc Random.h
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) Random.cc
thread.o: thread.cc thread.h
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) thread.cc
lwp_thread.o: lwp_thread.cc lwp_thread.h
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) lwp_thread.cc
gnu_thread.o: gnu_thread.cc gnu_thread.h
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) gnu_thread.cc
TestRandom: TestRandom.o $(OBJECTS) $(HEADERS) $(INLINES)
$(C++) -o TestRandom TestRandom.o $(LIB) $(LDFLAGS) $(LOCAL_LDFLAGS)
TestRandom.o: TestRandom.cc
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) TestRandom.cc
TestSet: TestSet.o $(OBJECTS) $(HEADERS) $(INLINES)
$(C++) -o TestSet TestSet.o $(LIB) $(LDFLAGS) $(LOCAL_LDFLAGS)
TestSet.o: TestSet.cc
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) TestSet.cc
$(LIB) : $(OBJECTS)
ar rv $@ $?
ranlib $(LIB)
clean:
rm -f *.o
vclean: clean
rm -f *~* libThreads.a TestRandom TestSet
.a
OBJECTS = Process.o ProcessIterator.o ProcessList.o ProcessCons.o \
Link.o Head.o Set.o Element.o \
thread.o lwp_thrC++SIM/gnu_thread.cc
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#include <iostream.h>
#include <sys/types.h>
#define _INIT_
#include <gnulwp.h>
#ifndef GNUTHREAD_H_
#include "gnu_thread.h"
#endif
long GNU_Thread::base_key = 0;
boolean GNU_Thread::DoWait = true;
boolean GNU_Thread::SuspendMain = false;
int GNU_Thread::count = 0;
const int GNU_Thread::MaxPriority = 7;
GNU_Thread::GNU_Thread (int prio)
{
to_wait = 0;
caddr_t p1;
initlp(MaxPriority);
p1 = (caddr_t) this;
thread_key = base_key++;
my_block = creatp(prio, GNU_Thread::Execute, 8000, 0, 0, p1);
}
GNU_Thread::~GNU_Thread () {}
void GNU_Thread::Execute (int dummy1, char** dummy2, GNU_Thread* p1)
{
// Do this to remove compiler warnings.
dummy1 = 0;
dummy2 = 0;
if ((p1->thread_key == 1) && (Self()->Current_Thread() == 0))
{
signals(p1->to_wait);
p1->Body();
}
else
{
p1->to_wait = creats(0);
p1->Suspend();
p1->Body();
}
}
void GNU_Thread::Suspend ()
{
if ((thread_key == 0) && (Self()->Current_Thread() == 0) && (count < 2))
count++;
if ((count == 2) && (!SuspendMain))
{
SuspendMain = true;
struct sem* p = creats(0);
waits(p);
}
if ((thread_key == 1) && (Self()->Current_Thread() == 0))
{
if (DoWait)
{
DoWait = false;
waits(to_wait);
}
}
else
waits(to_wait);
}
void GNU_Thread::Resume ()
{
if ((thread_key == 1) && (Self()->Current_Thread() == 0))
{
readyp(my_block);
to_wait = creats(0);
Suspend();
}
else
signals(to_wait);
}
long GNU_Thread::Current_Thread () const { return thread_key; }
void GNU_Thread::Initialize () { initlp(1); }
AGS) $(LOCAL_C++FLAGS) Set.cc
Element.o: Element.cc Element.h Element.n
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) Element.cc
Random.o: Random.cc Random.h
$(C++) -c $(CPPFLAGS) $(LOCAL_CPPFLAGS) $(C++FLAGS) $(LOCAL_C++FLAGS) Random.cc
thread.o: thread.cc thread.h
$(C++) -c $(CPPFLAGS) $(LOCALC++SIM/gnu_thread.h
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef GNU_THREAD_H_
#define GNU_THREAD_H_
#ifndef COMMON_H_
#include "common.h"
#endif
#ifndef THREAD_H_
#include "thread.h"
#endif
#define MINPRIO 2
class GNU_Thread : public Thread
{
public:
virtual void Suspend (); // Suspend an active thread
virtual void Resume (); // Resume a suspended thread
virtual void Body () = 0; // Body of "active" object (defined in the deriving class)
virtual long Current_Thread () const; // Returns current thread id
// Initialize must be called exactly once at the start of the program
static void Initialize ();
protected:
static const int MaxPriority; // Maximum priority of a thread
static long base_key;
GNU_Thread (int priority = MaxPriority); // Create thread with given (or maximum) priority
virtual ~GNU_Thread ();
private:
static void Execute (int, char**, GNU_Thread*); // This routine calls the 'main' object code
static boolean DoWait;
static boolean SuspendMain;
static int count;
long thread_key;
struct sem* to_wait;
struct pcb* my_block;
};
#endif
}
if ((thread_key == 1) && (Self()->Current_Thread() == 0))
{
if (DoWait)
{
DoWait = false;
waits(to_wait);
}
}
else
waits(to_wait);
}
void GNU_Thread::Resume ()
{
if ((thread_key == 1) && (Self()->Current_Thread() == 0))
{
readyp(my_block);
C++SIM/lwp_thread.cc
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef COMMON_H_
#include "common.h"
#endif
#ifndef LWPTHREAD_H_
#include "lwp_thread.h"
#endif
/* These are the Sun C routines which give access to threads. They have to be
* defined in this way. The multiple definitions for lwp_create are as a result
* of the way in which C++ allows C routines to be declared and the way in which
* Sun's lwp_create is defined.
*/
extern "C"
{
#include <lwp/stackdep.h>
int pod_setmaxpri(int);
int lwp_setstkcache(int, int);
#ifndef Scheduler_
#ifdef Main_
int lwp_create(thread_t*, void (*func)(), int, int, stkalign_t*, int);
#else
int lwp_create(thread_t*, void (*func)(LWP_Thread *), int, int, stkalign_t*, int, caddr_t);
#endif
#endif
int lwp_yield(thread_t);
int lwp_suspend(thread_t);
int lwp_resume(thread_t);
int lwp_setpri(thread_t, int);
int lwp_self(thread_t*);
int lwp_ping(thread_t);
int lwp_sleep(struct timeval);
}
//
// Class LWP_Thread
//
const int LWP_Thread::MaxPriority=10;
#ifdef __GNUG__
thread_t* LWP_Thread::firstThread = 0;
boolean LWP_Thread::done = false;
#endif
LWP_Thread::LWP_Thread (int prio)
{
caddr_t p1;
p1 = (caddr_t) this;
(void) lwp_create(&mid, LWP_Thread::Execute, prio, 0, lwp_newstk(), 1, p1);
thread_key = mid.thread_key;
(void) lwp_suspend(mid);
}
// For creating the LWP_Thread for "main"
LWP_Thread::LWP_Thread (thread_t tid)
{
thread_key = tid.thread_key;
}
LWP_Thread::~LWP_Thread () {}
long LWP_Thread::Current_Thread () const
{
thread_t tid;
(void) lwp_self(&tid);
return tid.thread_key;
}
void LWP_Thread::Execute (LWP_Thread *p1)
{
#ifdef __GNUG__
if ((LWP_Thread::firstThread == 0) && (!done))
{
LWP_Thread::firstThread = new thread_t;
(void) lwp_self(LWP_Thread::firstThread);
lwp_suspend(*LWP_Thread::firstThread);
}
#endif
p1->Body();
}
void LWP_Thread::Suspend ()
{
#ifdef __GNUG__
if ((LWP_Thread::firstThread != 0) && (!done))
{
done = true;
lwp_resume(*LWP_Thread::firstThread);
}
#endif
(void) lwp_suspend(mid);
}
void LWP_Thread::Resume ()
{
#ifdef __GNUG__
if ((LWP_Thread::firstThread != 0) && (done))
#endif
(void) lwp_resume(mid);
}
void LWP_Thread::Sleep (struct timeval doze) { (void) lwp_sleep(doze); }
thread_t LWP_Thread::Thread_ID () const { return mid; }
//
// Getting the main thread into the thread list...
//
class LWP_Main_Thread : public LWP_Thread
{
public:
LWP_Main_Thread (thread_t t) : LWP_Thread(t) {}
~LWP_Main_Thread ();
void Body ();
};
LWP_Main_Thread::~LWP_Main_Thread () {}
void LWP_Main_Thread::Body () {}
void LWP_Thread::Initialize ()
{
(void) pod_setmaxpri(MaxPriority);
(void) lwp_setstkcache(4000, 40);
thread_t me;
lwp_self(&me);
new LWP_Main_Thread(me);
}
lwp_create are as a result
* of the way in which C++ allows C routines to be declared and the way in which
* Sun's lwp_create is defined.
*/
extern "C"
{
#incC++SIM/lwp_thread.h
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef LWP_THREAD_H_
#define LWP_THREAD_H_
#include <lwp/lwp.h>
#ifndef THREAD_H_
#include "thread.h"
#endif
/* This is the Sun thread implementation of the Thread virtual class. It provides
* an implementation for all of the pure virtual functions declared in the Thread
* base class.
* The Initialize function must be called at the start of any program which uses the
* threads implementation as it calls necessary Sun thread initialization routines.
*
* Note: if any problems occur when using the Sun thread package, try increasing the
* stack size and/or the number of stacks to create in Initialize.
*/
class LWP_Thread : public Thread
{
public:
virtual void Suspend (); // Suspend an active thread
virtual void Resume (); // Resume a suspended thread
virtual void Sleep (struct timeval); // Put active thread to sleep for duration specified
virtual void Body () = 0; // Body of "active" object (defined in the deriving class)
virtual long Current_Thread () const; // Returns current thread id
thread_t Thread_ID () const; // Returns current thread's Sun thread_key
// Initialize must be called exactly once at the start of the program
static void Initialize ();
protected:
static const int MaxPriority; // Maximum priority of a thread
LWP_Thread (int priority = MaxPriority); // Create thread with given (or maximum) priority
LWP_Thread (thread_t); // Create thread with given Sun thread_key
virtual ~LWP_Thread ();
private:
static void Execute (LWP_Thread*); // This routine calls the 'main' object code
#ifdef __GNUG__
static thread_t* firstThread;
static boolean done;
#endif
thread_t mid;
};
#endif
spend(*LWP_Thread::firstThread);
}
#endif
p1->Body();
}
void LWP_Thread::Suspend ()
{
#ifdef __GNUG__
if ((LWP_Thread::firsC++SIM/thread.cc
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef THREAD_H_
#include "thread.h"
#endif
class Thread *Thread::head = 0; // Initialise head of Thread list
Thread::Thread ()
{
Thread *marker = head;
if (head != 0)
{
while (marker->next != 0)
marker = marker->next;
marker->next = this;
marker->next->prev = marker;
marker = marker->next;
marker->next = 0;
}
else
{
this->prev = 0;
this->next = 0;
head = this;
}
thread_key = 0;
// Actual thread key value MUST be set in derived class constructor
}
Thread::~Thread ()
{
if (this->prev != 0)
this->prev->next = this->next;
else
head = this->next;
}
long Thread::Identity () const { return thread_key; }
Thread *Thread::Self ()
{
if (!head) return 0;
// Use any thread object (e.g., head) to get access to the current thread
long my_id = head->Current_Thread();
for (Thread *marker = head; marker; marker=marker->next)
if (marker->thread_key == my_id)
break;
return marker;
}
ct (defined in the deriving class)
virtual long Current_Thread () const; // Returns current thread id
thread_t Thread_ID () const; // Returns current thread's Sun thread_key
// Initialize must be called exactly once at the start of the program
static void Initialize ();
protected:
static const int MaxPriority; // Maximum priority of a thread
LWP_Thread (int priority = MaxPriority); // CrC++SIM/thread.h
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#ifndef THREAD_H_
#define THREAD_H_
/* This class defines a template for threads packages which will be used to
* provide "active" objects in C++. Such objects are not derived from this
* class, but instead a thread implementation class is derived from this.
* That class will then define the pure virtual functions, and "active" objects
* are then derived from that class.
* Because not every thread package provides an easy way of identifying and locating
* threads, the Thread class does provide such a scheme through the use of the
* Identify and Self operations. A linked list of threads is formed and added to
* whenever a new thread is created.
*/
class Thread
{
public:
virtual void Suspend () = 0; // How to suspend a thread
virtual void Resume () = 0; // How to resume a suspended thread
virtual void Body () = 0; // The 'main' part of the code
virtual long Current_Thread () const = 0; // Should return some unique thread identity key
virtual long Identity () const; // Returns the identify of this thread
static Thread *Self (); // Returns the current thread
protected:
Thread ();
virtual ~Thread ();
long thread_key;
private:
Thread *next, *prev;
static Thread *head;
};
#endif
tatic void Initialize ();
protected:
static const int MaxPriority; // Maximum priority of a thread
LWP_Thread (int priority = MaxPriority); // CrC++SIM/Process.n
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#if defined(NO_INLINES) && !defined(PROCESS_CC_)
#else
#ifndef NO_INLINES
# define INLINEF inline
#else
# define INLINEF
#endif
INLINEF void Process::set_evtime (double time)
{
wakeuptime = time;
}
INLINEF void Process::Activate ()
{
ReActivate();
}
INLINEF double Process::evtime () const
{
return wakeuptime;
}
INLINEF boolean Process::terminated () const
{
return Terminated;
}
#ifdef INLINEF
# undef INLINEF
#endif
#endif
* The University,
* Newcastle upon Tyne,
* UK.
*/
#if defined(NO_INLINES) && !defined(PROCESS_CC_)
#else
#ifndef NO_INLINES
# define INLINEF inline
#else
# define INLINEF
#endif
INLINEF void Process::set_evtime (double time)
{
wakeuptime = time;
}
INLINEF void Process::Activate ()
{
ReActivate();
}
INLINEF double Process::evtime () const
{
return wakeuptime;
}
INLINEF boolean Process::terminated () const
{
returnC++SIM/Process.cc
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#include <iostream.h>
#include <stdlib.h>
#ifndef COMMON_H_
#include "common.h"
#endif
#ifndef PROCESS_H_
#include "Process.h"
#endif
#ifndef PROCESSITERATOR_H_
#include "ProcessIterator.h"
#endif
#ifndef PROCESSLIST_H_
#include "ProcessList.h"
#endif
#ifndef PROCESSCONS_H_
#include "ProcessCons.h"
#endif
static ProcessList ReadyQueue;
static Process *Current = 0;
//
// create scheduler task at MINPRIO
//
Scheduler::Scheduler () : Thread_Type(MINPRIO) {}
Scheduler::~Scheduler () {}
void Scheduler::Body ()
{
for (;;)
{
Current = ReadyQueue.Remove();
if (Current == 0) // all done
{
#ifdef DEBUG
cerr << "Scheduler queue is empty.\n";
#endif
exit(0);
}
if (Current->evtime() < 0)
cerr << "Scheduler Error: Process WakeupTime Invalid.\n";
else
SimulatedTime = Current->evtime();
#ifdef DEBUG
cerr << "Simulated time is now " << SimulatedTime << "\n";
#endif
Current->Resume();
}
}
double Scheduler::CurrentTime () const { return SimulatedTime; }
//
// Class Process
//
const int Process::Never=-1; // Process will never awaken.
Process::~Process () {}
double Process::CurrentTime () { return SimulatedTime; }
double Process::Time () const { return SimulatedTime; }
void Process::ActivateBefore (Process &p)
{
// No op if already scheduled
if (idle()) return;
if (ReadyQueue.InsertBefore(*this, p))
wakeuptime = p.wakeuptime;
else
cerr << "ActivateBefore failed because 'before' process is not scheduled" << endl;
}
void Process::ActivateAfter (Process &p)
{
// No op if already scheduled
if (idle()) return;
if (ReadyQueue.InsertAfter(*this, p))
wakeuptime = p.wakeuptime;
else
cerr << "ActivateAfter failed because 'after' process is not scheduled" << endl;
}
void Process::ActivateAt (double AtTime, boolean prior)
{
// No op if already scheduled
if (idle()) return;
wakeuptime = AtTime;
ReadyQueue.Insert(*this, prior);
}
void Process::ActivateDelay (double Delay, boolean prior)
{
// No op if already scheduled
if (idle()) return;
wakeuptime = SimulatedTime + Delay;
ReadyQueue.Insert(*this, prior);
}
// Similarly, there are four ways to reactivate
// Note that if a process is already scheduled, the reactivate
// will simply re-schedule the process.
void Process::ReActivateBefore (Process &p)
{
Cancel();
ActivateBefore(p);
}
void Process::ReActivateAfter (Process &p)
{
Cancel();
ActivateAfter(p);
}
void Process::ReActivateAt (double AtTime, boolean prior)
{
Cancel();
ActivateAt(AtTime, prior);
}
void Process::ReActivateDelay (double Delay, boolean prior)
{
Cancel();
ActivateDelay(Delay, prior);
}
void Process::ReActivate ()
{
if (idle())
ReadyQueue.Remove(this);
set_evtime(CurrentTime());
Resume();
}
// cancels next burst of activity, process becomes idle
void Process::Cancel ()
{
if (idle())
ReadyQueue.Remove(this);
else
Suspend();
wakeuptime = Process::Never;
}
boolean Process::idle ()
{
if (wakeuptime == CurrentTime())
return false;
else
return true;
}
Process::Process() : Thread_Type()
{
wakeuptime = CurrentTime();
}
// suspend current process for simulated time t
void Process::Hold (double t)
{
ActivateDelay(t);
Suspend();
}
// suspend current process indefinitely (i.e., make idle)
void Process::Passivate ()
{
wakeuptime = Process::Never;
this->Terminated = true;
Suspend();
}
#ifdef NO_INLINES
# define PROCESS_CC_
# include "Process.n"
# undef PROCESS_CC_
#endif
private:
double Mean,StandardDeviation;
double p;
};
class NormalStream : public RandomStream
{
public:
NormalStream (double Mean, double StandardDeviation, int StreamSelect=0);
virtual double operator() ();
private:
double Mean,StandardDeviation;
double z;
};
#endif // RANDOM_H
lgorithms, Knuth, Addison-Wesley, p.117
double X2;
if (z!=0.0) {
X2 = z;
z = 0.0;
} else {
double SC++SIM/Version
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
This is version 1.1 of C++SIM. The only changes from 1.0 are bug fixes in
the code and enhancements to allow it to work with g++ and Sun's lwp
package at the same time (up until now if you wanted to use g++ you had to
use their threads package too).
Mark Little 16/7/93.
CONS_H_
#include "ProcessCons.h"
#endif
static ProcessList ReadyQueue;
static Process *Current = 0;
//
// create schedu
* Copyright (C) 1993
*
* Department of Computing Science,
* The University,
* Newcastle upon Tyne,
* UK.
*/
#if defined(NO_INLINES) && !defined(PROCESS_CC_)
#else
#ifndef NO_INLINES
# define INLINEF inline
#else
# define INLINEF
#endif
INLINEF void Process::set_evtime (double time)
{
wakeuptime = time;
}
INLINEF void Process::Activate ()
{
ReActivate();
}
INLINEF double Process::evtime () const
{
return wakeuptime;
}
INLINEF boolean Process::terminated () const
{
return
}