- You could just spawn a thread and call
- Recurring UI timers, with 10ms resolution
- One-off alarms, with 100ms resolution
- I/O timeouts system with 5 second resolution
None of these were satisfactory. The thread approach is fine for the most part, except there was no way to interrupt a sleeping thread. The other two approaches had low resolution because they relied on a thread which would poll some kind of timer queue for events.
I unified all these approaches with a new
alarmsvocabulary which does not rely on polling, instead an alarm thread is woken up when alarms are added. To achieve this, I added a new word to the
nap. It is like
sleepexcept other threads can interrupt the sleep with
napword returns a boolean indicating whether it was interrupted or not.
The alarm thread naps until the next alarm is set to go off, however if a new timer is added in the mean time which would go off sooner, the thread is interrupted. This means it no longer has to poll regularly, and also increases accuracy.
The alarm API is straightforward:
add-alarm ( quot time frequency -- alarm )adds an alarm which first fires at
timeand then every
frequencytime units thereafter. The timestamp and time deltas are the
dttypes defined in the
calendarvocabulary; no need to mess around with integers represeting milliseconds.
cancel-alarm ( alarm -- )cancels a pending alarm.
later ( quot delay -- alarm )runs a quotation once, a fixed delay from now. Code which calls it looks almost like English:
[ "Hello world" print ] 5 minutes later
Alarms are stored in a min-heap for efficiency, and the
cancel-alarmword uses a new feature of heaps, namely the ability to remove an entry in O(log n) time.
Until now the
set-timeoutword for streams, as well as timeouts for the process launcher took integers denoting time counts in milliseconds. That is so 1970's. Instead the new style is strongly-typed time units from the
1 minutes stdio get set-timeout
sleepword is generic, and if
calendaris loaded it has methods which accept time units as well:
5 minutes sleep
30 seconds sleep
10 milliseconds sleep
Timeouts for locks, semaphores, promises, futures, message sends
concurrency.messaginglibrary for Erlang-style message passing finally supports timeouts (strongly-typed, as above). The other concurrency abstractions do as well. All of this is implemented on top of the same underlying framework which in turn sits on top of alarms, which in turn use