[ Event Handling | Reference Manual | Alphabetic Index ]

event_after_every(+Event, +Time)

Set up an event Event which is triggered after every Time seconds have elapsed.
Atom or Handle
Positive number


The event Event is raised after every Time seconds of elapsed time from when the predicate is executed. The difference from event_after/2 and event_after/3 is that event_after_every/2 raises the event Event at regular Time intervals once it is initiated, whereas event_after/2 and event_after/3 raise the event once (per event_after/2 and event_after/3) only. The time for the next event starts counting from the moment the previous event is raised. This means that the time between the raising of two events will never fall below the Time interval, even if there is a delay in raising one of the events. The event mechanism is safe with respect to backtracking: once an after-event has been requested, it will be raised, even when execution fails across the point where it was requested. The only way to stop further after-every-events being raised is to cancel them using cancel_after_event/2.

Time can be a real number, but the actual granularity of how fine the elapsed time is measured is operating system dependent, and the triggering condition is actually that at least Time seconds have elapsed.

In addition, the processing of an event may not happen immediately upon the raising the event, as events are processed synchronously: An event can only be handled at a point where an ECLiPSe goal can be executed. This can delay the handling of an event when ECLiPSe is performing some uninterruptible task, e.g. waiting for I/O, or executing external code.

The use of after-events requires some thought because after-events can be raised at unpredictable (even though well-defined) points during program execution. As long as the handlers succeed, this poses no particular problem, because execution is allowed to continue after the handler succeeds. By design, the possibilities of an event handler to interact with the interrupted execution are limited (the handler can access global data structures, use a symbolic trigger, etc).

More problematic are applications where the handler is allowed to abort using throw/1. Due to the timed execution, the exact program point where the abort happens is unpredictable. It must be made sure that the abort is safely caught in all cases, and that nonlogical data is not left in an inconsistent state. In such cases, it is possible to use events_defer/0 and events_nodefer/0 to protect critical code sequences from being interrupted by event handling. Note that it never makes sense to let after-event handlers fail.

Another problem that may occur with timed events is that a new event may be raised while another one is still being handled. To stop event handlers from being interrupted by others, it is possible to give events the defer-property. This means that event handling is automatically deferred on entering the event's handler, thus preventing other events from interrupting the handler. Such handlers must always explicitly invoke events_nodefer/0 before exiting in order to reenable event handling.

The timer used by measuring elapsed time is specified by the environment flag after_event_timer: virtual means that elapsed user cpu time is used, real means elapsed real time. The default is real. On systems that cannot support CPU time measurement, such as Microsoft Windows, one may not set the timer to virtual: an error is raised if this is attempted. The time relevant for event handling can be obtained by calling statistics(event_time, Now).

Modes and Determinism


(5) type error
Event is neither an atom nor a handle or Time is not a positive number.


    ?- event_create((statistics(event_time,T),writeln(now(T))), [], E),
	event_after_every(E, 1),
    now(4.61)	% after 1 second
    now(5.62)	% after 2 seconds

See Also

event_after / 2, event_after / 3, events_after / 1, cancel_after_event / 2, event / 1, set_event_handler / 2, current_after_events / 1, event_create / 3, event_retrieve / 3, get_flag / 2