|
Events are used
to synchronize the operations of CSIM
processes. An event exists in one of two
states: occurred
or not
occurred.
A process can change the state of an event
or it can suspend its execution until
an event has occurred. When a process
is suspended it can join a set of processes,
all of which will be resumed when the
event occurs. Or, it can join an ordered
queue from which only one process is resumed
for each occurrence of the event. An event
is automatically reset to the not
occurred
state when all of the suspended processes
that can proceed have done so.
Advanced features
of events include the ability to create
sets of events for which processes can
wait and the ability for a process to
bound its waiting time by specifying a
time-out. Events can also be used to construct
other synchronization mechanisms such
as semaphores.
A pointer to a dynamic
event is declared in a CSIM program as
follows:
Dynamic Example:
event *ed;
Before a dyanmic event can be used, it
must be initialized by invoking the new
event constructor.
Prototype:
event::event(char
*name)
Static
Example:
event es("done");
Dynamic
Example:
ed = new
event("done");
An event is initialized
in the not
occurred
state. The event name is used only to
identify the event in output reports and
trace messages.
An event that is initialized in the first
CSIM process (sim) exists during the entire
simulation run and is called a global
event. An event initialized in any other
process is called a local event. A local
event is deleted when the process in which
it was initialized terminates. To make
such an event exist for the entire run,
it must be initialized by calling the
global_event
function.
Prototype:
global event::global_event
(char *name)
Static
Example: global_event
es("done");
Dynamic
Example: ed
= new global_event("done");
A process waits
for an event to occur by calling the wait
function.
Prototype:
void event::wait(void)
Dynamic
Example:
e->wait();
If the event is
in the occurred
state, control returns from the wait function
immediately and the event is changed to
the not
occurred
state. If the event is in the not
occurred
state, the calling process is suspended
from further execution and control will
not return from the wait
function until some other process sets
this event. When the event is set, all
waiting processes will be resumed and
the event will be placed in the not
occurred
state.
Sometimes a process
must not be suspended indefinitely waiting
for an event to occur. If a process calls
the timed_wait
function, it will be suspended until either
the event is set or the specified amount
of time has passed.
Prototype:
long event::timed_wait(double
timeout)
Dynamic
Example: result
= ed->timed_wait(100.0);
if (result ! = TIMED_OUT)
The calling process
should check the functional value to determine
the circumstances under which it was resumed.
If the value EVENT_OCCURRED is returned,
the process was activated because the
event has occurred; if the value TIMED_OUT
is returned, the specified amount of time
passed without the event being set.
A process joins
the ordered queue for an event by calling
the queue function.
Prototype:
void event::queue(void)
Dynamic
Example:
ed->queue();
This function
behaves similarly to the wait
function, except that each time the event
is set only one queued process is resumed.
The queue is maintained in order of process
priority, with processes having the same
priority being ordered by time of insertion
into the queue.
If a process calls
the
timed_queue
function, it will be suspended until either
the event is set a sufficient number of
times for the process to be activated
or the specified amount of time has passed.
Prototype:
long event::timed_queue(double
timeout)
Dynamic
Example:
result =
ed->timed_queue(100.0);
if (result ! = TIMED_OUT) ...
The calling process
should check the functional value to determine
the circumstances under which it was resumed.
If the value EVENT_OCCURRED is returned,
the process was activated because the
event occurred; if the value TIMED_OUT
is returned, the specified amount of time
passed without the process being activated
by the event being set.
A process can
put an event into the occurred
state by calling the set
function.
Prototype:
void event::set(void)
Dynamic
Example:
ed->set();
Calling this function
causes all waiting processes and one queued
process to be resumed. If there are no
waiting or queued processes, the event
will be in the occurred
state upon return from the set
function. If there are waiting or queued
processes, the event will be in the not
occurred
state upon return. No simulation time
passes during these activities. Setting
an event that is already in the occurred
state has no effect.
A process can
put an event into the not
occurred
state by calling the clear
function.
Prototype:
void event::clear(void)
Dynamic
Example:
ed->clear();
Clearing an event
happens in zero simulation time and no
processes are in any way affected. Clearing
an event that is already in the not
occurred
state has no effect.
The name of an
event can be changed at any time using
the set_name_event
function.
Prototype:
void event::set_name(char
*new_name)
Dynamic
Example:
es->set_name_event("finished");
Only the first
ten characters of the event's name are
stored.
When a dynamic
event is no longer needed, its storage
can be reclaimed using the delete
function.
Dynamic Example:
delete ed;
If an event is
local, only the process that created the
event can delete it. Once an event has
been deleted, it must not be further referenced.
It is an error to attempt to delete an
event on which processes are waiting or
queued.
A set of statistics
on the usage can be collected for specified
events. Statistics collection for an event
is initiated by executing the monitor()
method.
Prototype:
void event::monitor(void
)
Dynamic
Example:
e->monitor();
The standard report
function automatically proceeds to "print"
a report for each monitored event. This
report is as follows:
| EVENT
SUMMARY |
| event of name |
number of
queue vst |
qvg que length |
avg time queued |
number of
wait vsts |
avg wait length |
avg time waiting |
number set
ops |
| ev |
10 |
0.99010 |
1.00000 |
50 |
4.95050 |
1.00000 |
10 |
A separate for all of
the monitored events is produced using
the report_events() procedure, as follows:
Prototype:
void report_events(void )
Example:
report_events();
All of the events in
an event_set (see below) can be monitored
as well.
Prototype:
void event_set::monitor(void)
Dynamic Example:
es->monitor();
In some cases, it is
necessary to reset the statistics counters
for a specific event.
Prototype:
void event::reset(void)
Example:
e->reset();
Executing this statement
does not affect the state of the event.
The "reset" and the reset_events
statements each call reset_event() for
all events in the model.
An event set is an array
of related events for which some special
operations are provided. A pointer to
a dynamic event set is declared as follows:
Example:
event_set *ed_set;
All events in an event
set are initialized by invoking the event_set
constructor.
Prototype:
event_set::event_set(char
*name, long number_of_events)
Static Example:
event_set es_set("events",
10);
Dynamic Example:
ed_set =
new event_set("events",10);
As with any C array,
the events in an event set are indexed
from 0
to num_events
- 1. Individual events in the event
set can be manipulated using any of normal
event functions (e.g.,
set, clear, wait, queue).
Static
Example: es_set[3].set();
Dynamic Example:
(*ed_set)[3].set();
A process can wait for
the occurrence of any event in an event
set by calling the wait_any
function.
Prototype:
long event_set::wait_any(void)
Dynamic Example:
event_index
= ed_set->wait_any();
This function returns
the index of the event that caused the
calling process to proceed. If multiple
events in the set are in the occurred
state, the lowest numbered event is the
one recognized by the calling process.
All processes that have called wait_any
are activated by the next event that occurs,
and these processes all receive the same
index value.
A process can join an
ordered queue for an event set by calling
the queue_any
method.
Prototype:
long event_set::queue_any(void)
Dynamic Example:
event_index = ed_set->queue_any();
Each time any event
in the event set occurs, one process in
the queue is activated. The functional
value is the same as that of the wait_any
function. It is not currently possible
to specify a time-out for the wait_any
or queue_any
methods.
An entire dynamic event
set is deleted as follows:
Example:
delete e_set;
It is an error to delete
individual elements of an event set.
A process can also do
a time_wait_any() operation at an event_set.
Prototype:
long event_set::timed_wait_any(double
time_out)
Dynamic Example:
result = ed_set->time_wait_any(double
time_out);
If the result is not
equal to TIME_OUT, the it is index of
the event which caused the process to
continue.
A process can also do
a timed_queue_any() operation at an event_set:
Prototype:
long event_set::timed_queue_any(double
time_out)
Dynamic Example:
result = ed_set->time_queue_any(double
time_out);
If the result is not
equal to TIMED_OUT, then it is the index
of the event which caused the process
to continue.
7.13. Inspector Methods
The following methods
return information about the specified
event at the time they are called
| Prototype: |
Functional
value: |
| char
*event::name() |
pointer
to name of event |
| long event::wait_cnt() |
number of processes
waiting for event |
| long
event::queue_cnt() |
number
of processes queued of event |
| long event::qlen() |
sum of wait_cnt
and queue_cnt |
| long
event::state() |
state
of event:
OCC if occurred or
NOT_OCC if not occurred |
| long event::num_events() |
number of processes
waiting for the event |
| long
event::set_count() |
number
of set operations |
| double event::queue_sum() |
sum of queue queue
lengths |
| double
event::wait_sum() |
sum
of wait queue lengths |
| long event::queue_delay_count() |
number of queue
delays |
| long
event::wait_delay_count() |
number
of wait delays |
| long event::queue_length() |
average queue queue
length |
| long
event::wait_length() |
average
wait queue length |
| long event::queue_time() |
average queue queue
time |
| long
event::wait_time() |
average
wait queue time |
| long event::queue_count() |
average queue queue
count |
| long event::wait_count() |
average wait queue
count |
The status_events
function prints a report of the status
of all events in the model.
Prototype:
void status_events(void)
Example:
status_events();
For each event, the
report includes its state, the number
of processes waiting for it, the number
of processes queued for it, the name and
id of all waiting processes, and the name
and id of all queued processes. The report
is written to the default output stream
or the stream specified in the last call
to set_output_file.
A process can suspend
itself until there are no other active
processes by waiting on the built-in event
event_list_empty.
Example:
event_list_empty.wait();
This event is automatically
set by CSIM when all processes have terminated
or are waiting for something (e.g.,
a facility or storage). Modelers sometimes
use this to force the initial (sim) process
to wait until all work in the system being
modeled has completed. Upon being reactivated,
the initial process might then produce
reports.
If run length control
is involved for a table, qtable, meter
or box, (see 14.3), a process can suspend
itself until the run length control mechanism
signals the end of a run. This is done
by waiting for the built-in event converged.
Example:
converged.wait()
Next
Section
|