Buffer
is a concrete class derived from Atomic
. This
class has a single input port in
, an
-vector of input
ports pull
and an
- vector of output ports out
(in this example,
=3). As member data, phase
is a
string; m_Clients
is a buffer keeping incoming clients
whose type is tmValue
; m_OAvail
is a vector of
boolean values tracking the availability of servers;
m_OSzie
stores the number of connected servers; and
send_index
is an int
which tracks the server index
to which Buffer
will send output.
class Buffer: public Atomic { public: InputPort* in; vector<InputPort*> pull; vector<OutputPort*> out; protected: string m_phase; deque<tmValue*> m_Clients; vector<bool> m_OAvail; const int m_Osize; int send_index;
The function C1
updates member data as a function of an
input event x
. If x
comes through the input port
in
, C1
casts the value of x
to tmValue
and pushes it back to the buffer m_Clients
. Otherwise,
x
comes through one of pull
ports. So C1
searches the server index i
, checking the identity of
pull[i]
and the incoming event's port, and updates
m_OAvail[i]=true
which marks the i
-th server as
being available.
void C1(const PortValue& x) { if(x.port == in){ //receiving a client tmValue* client = dynamic_cast<tmValue*>(x.value); if(client) { m_Clients.push_back(client); } else THROW_DEVS_EXCEPTION("Dynamic Casting Failed!"); } else // receiving a pull signal { for(int i=0; i<m_Osize; i++) { if(x.port == pull[i]) { m_OAvail[i]= true; // server_i is available break; } } } }The function
Matched()
first checks to see if there is a
waiting client in m_Clients
and then checks to see if there
exists an available server from 0 to m_Osize
-1. If a match
is found, the function sets m_OAvail[i]=false
, remembers
the index i
at send_index
, then returns true
.
Otherwise it returns false
which means no match.
bool Matched() { if(m_Clients.empty() == false){ for(int i=0; i < m_Osize; i++){// select server if(m_OAvail[i] == true){// server i is available m_OAvail[i]=false;//Mark server_i non-available send_index = i; // remember i in send_index return true; } } return false; }else return false; }
The function C2
creates an the output event and removes the
first client from m_Clients
when C2
's phase is
SENDTO
.
void C2(PortValue& y) { if(m_phase == SENDTO){ y.Set(out[send_index], m_Clients[0]); m_Clients.pop_front();// remove the first client } }
The function init()
of Buffer
resets phase to
IDLE
, assigns m_OAvial[i]=true
for all indices, and
clears
all clients in m_Clients
.
/*virtual*/ void init() { m_phase = IDLE; m_OAvail.clear(); // clear first for(int i=0; i<m_Osize; i++) m_OAvail.push_back(true); // add variable while(m_Clients.empty() == false) { tmValue* cl = m_Clients[0]; m_Clients.pop_front(); delete cl; } }
Buffer
's tau()
returns
for IDLE
and
returns 2.0 for SENDTO
.
/*virtual*/ Time tau() const { if(m_phase == IDLE) return DBL_MAX; else return 2.0; }The input transition function
delta_x
of Buffer
updates member data by calling C1(x)
and then, if the phase
of the server is IDLE
, checks the returning value of
Matched()
. If the value is true
, the phase of the
server changes into SENDTO
.
/*virtual*/ bool delta_x(const PortValue& x) { C1(x); if(m_phase == IDLE){ if(Matched()){ m_phase = SENDTO; return true; // reschedule as active } } return false; }
When the server is ready to exit the SENDTO
state, it gets
y
by calling C2(y)
, if Matched()
returns
true
, the phase stays at SENDTO
. Otherwise, the
phase returns to IDLE
.
/*virtual*/ void delta_y(PortValue& y) { C2(y); if(Matched()) m_phase = SENDTO; else m_phase = IDLE; }
Recall that Buffer
class contains the overriding
Get_Statistics_s()
and GetPerformance()
, which were
investigated in Section 4.2.3. For the
codes of Buffer::Get_s()
, the reader should refer to
Buffer.h
.