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.
An event is declared in a CSIM program
using the built-in type EVENT.
Example:
EVENT e;
Before an event can be used, it must
be initialized by calling the event
function.
Prototype:
EVENT event(char* name)
Example:
e = 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:
EVENT global_event(char* name)
Example:
e = global_event("done");
A process waits for an event to occur
by calling the wait
function.
Prototype:
void wait(EVENT
e)
Example:
wait(e);
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 timed_wait(EVENT e, double timeout)
Example:
result = timed_wait(e,
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 queue(EVENT e)
Example:
queue(e);
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 timed_queue(EVENT e,
double timeout)
Example: result = timed_queue(e, 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 set(EVENT e)
Example:
set(e);
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 clear(EVENT e)
Example:
clear(e);
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 set_name_event(EVENT
e, char *new_name)
Example:
set_name_event(e,
"finished");
Only the first ten characters of the
event's name are stored.
When an event is no longer needed, its
storage can be reclaimed using the delete_event
function.
Prototype:
void delete_event(EVENT
e)
Example:
delete_event(e);
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 event_monitor statement.
Prototype:
void event_monitor(EVENT e)
Example:
event_monitor(e);
The standard report function automatically
proceeds to "print" a report
for each monitored event. This report
is as follows:
A report for all of the monitored events
can be generated as follows:
Prototype:
void report_events()
Example:
report_events();
All of the events in an event_set (see
below) can be monitored as well.
Prototype:
void event_set_monitor(EVENT
es[])
Example:
event_set_monitor(es);
In some cases, it is necessary to reset
the statistics counters for a specific
event.
Prototype:
void reset_event(EVENT e)
Example:
reset_event(e);
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. An event set is declared
using the C array construct.
Example:
EVENT e_set[10];
All events in an event set are initialized
with a single call to the event_set
function.
Prototype:
void event_set(EVENT
e_set[], char *name,
long number_of_events)
Example:
event_set(e_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).
Example:
set(e_set[3]);
A process can wait for the occurrence
of any event in an event set by calling
the wait_any
function.
Prototype:
long wait_any(EVENT
e_set[])
Example:
event_index
= wait_any(e_set);
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
function.
Prototype:
long queue_any(EVENT
e_set[])
Example:
event_index =
queue_any(e_set);
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
functions.
An entire event set is deleted by calling
the delete_event_set
function.
Prototype:
void delete_event_set(EVENT
e_set[])
Example:
delete_event_set(e_set);
The delete_event
function must not be called on individual
members of an event set.
A process can also do a timed_wait_any()
operation at an event_set.
Prototype:
long timed_wait_any(EVENT
e_set[], double to)
Example:
result = time_wait_any(e_set,
1.0);
if(result != TIMED_OUT) . . .
If the result is not equal to TIMED_OUT,
then it is the 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 timed_queue_any(EVENT
e_set[], double to)
Example:
result = time_queue_any(e_set,
1.0);
if(result != TIMED_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 Functions
The following functions return information
about the specified event at the time
they are called.
| Prototype: |
Functional
value: |
| char* event_name(EVENT
e) |
pointer to name
of event |
long wait_cnt(EVENT e) |
number of processes
waiting for
event |
| long queue_cnt(EVENT
e) |
number of processes
queued of
event |
| long event_qlen(EVENT
e) |
sum of wait_cnt
and queue_cnt |
| long state(EVENT
e) state of event: |
OCC if occurred
or
NOT_OCC if not occurred |
| long num_events |
number of events
in event_set |
| 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 |
| double event_queue_length |
average queue
queue length |
| double event_wait_length |
average wait
queue length |
| double event_queue_time |
average queue
queue time |
| double event_wait_time |
average wait
queue time |
| long event_queue_count |
number of queue
operations |
| long event_wait_count |
number of wait
operations |
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:
wait(event_list_empty);
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
section 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:
wait(converged);