Standard Library
class Timer
A source of ticks on the event loop.
since 0.1.0-alpha.1linuxwindows
Overview
A timer is a stream: the event loop pushes tick numbers 1, 2, 3, ... into it, so subscribe and for loops over ticks() work as with any other stream. Create one with after for a single tick or every for a repeating one, or with the constructor for a separate first delay and interval. The program keeps running while a timer is live; a one-shot timer releases itself after it fires, and cancel releases a repeating timer.
Callbacks run one at a time on the loop thread, never at the same moment.
Description
A timer is a stream. The event loop pushes a tick number into it each time the timer fires,
counting from 1, so all the ordinary stream tools (subscribe, pull, for ... in) work on it.
You create timers with two functions in std:
std::after(ms)is a one-shot timer: it fires once,msmilliseconds from now, and then releases itself.std::every(ms)is a repeating timer: it fires everymsmilliseconds until you cancel it.
A Timer has three members. ticks() returns an InStream<int> over the tick numbers,
subscribe(callback) is shorthand for subscribing to those ticks, and cancel() stops the timer
and releases the work it holds.
A timer that is waiting to fire keeps the program alive (see lang.event-loop). That is why a
repeating timer needs a cancel(): without one, the program never exits.
Reading ticks, then counting them
Timer t = std::every(10);
InStream<int> ticks = t.ticks();
int total = 0;
for (int n in ticks) {
total += n;
if (n == 4) { t.cancel(); ticks.close(); }
}
console.writeln("sum of ticks: ${total}");
Timer one = std::after(5);
one.subscribe((n) => console.writeln("tick number is ${n}"));
sum of ticks: 10
tick number is 1
Rules
- Tick numbers start at
1and increase by one each firing. - A one-shot timer fires exactly once, so its only tick is
1. cancel()stops a timer; a one-shot releases itself after firing and needs no cancel.- Timers share the stream rules: one consumer, so
subscribeandfor ... inover the same timer are mutually exclusive. To end aforloop over a repeating timer, callcancel()and close the stream, as the example does. - Timers due at the same moment fire in the order they were created.
- A timer callback runs on the event loop and never concurrently with other code. An uncaught
exception in it stops the loop and ends the program with status
1.
Examples
Three timers created out of order still fire in due-time order:
One-shot timers fire when due
Timer slow = std::after(30);
Timer fast = std::after(10);
Timer medium = std::after(20);
slow.subscribe((n) => console.writeln("slow"));
fast.subscribe((n) => console.writeln("fast"));
medium.subscribe((n) => console.writeln("medium"));
fast
medium
slow
Notes
Bare std::sysTimerStart(delayMs, intervalMs, callback) is the public low-level form the two
functions are built on; see lang.system-floor. Prefer std::after and std::every, because
they give you the Timer to cancel.
Examples
A repeating timer that cancels itself after three ticks
Timer t = Timer(5, 5);
t.subscribe((n) => {
console.writeln("tick ${n}");
if (n == 3) {
t.cancel();
console.writeln("cancelled");
}
});
tick 1
tick 2
tick 3
cancelled
Constructors
new
new(int delayMs, int intervalMs)Start a timer.
The first tick comes after delayMs milliseconds. A positive intervalMs makes the timer repeat at that interval; 0 makes it fire once.
Parameters
- delayMs
- Milliseconds until the first tick.
- intervalMs
- Milliseconds between later ticks;
0for a single tick.
Examples
Timer once = Timer(5, 0);
once.subscribe((n) => { console.writeln("fired, tick ${n}"); });
console.writeln("timer started");
timer started
fired, tick 1
Methods
cancel
cancel() -> voidStop the timer.
No further ticks are delivered, and a repeating timer stops keeping the program alive. Cancelling a timer that already fired once, or one that was already cancelled, does nothing.
Examples
Timer t = std::every(5);
t.subscribe((n) => {
console.writeln("tick ${n}");
if (n == 2) {
t.cancel();
console.writeln("stopped");
}
});
tick 1
tick 2
stopped
subscribe
subscribe((int) => void cb) -> voidCall a function on every tick.
The callback receives the tick number. This claims the timer's stream, so it cannot be combined with ticks.
Parameters
- cb
- The function to call with each tick number.
Examples
Timer t = std::every(5);
t.subscribe((n) => {
console.writeln("tick ${n}");
if (n == 2) { t.cancel(); }
});
tick 1
tick 2
ticks
ticks() -> InStream<int>Get the timer's ticks as a stream.
Each tick is the number of the tick, counting from 1. Iterating the stream waits for each tick as it arrives. The stream is claimed by the first reader, so use either ticks or subscribe, not both.
Returns
A stream of tick numbers.
Examples
Timer rep = std::every(5);
for (int tick in rep.ticks()) {
console.writeln("tick ${tick}");
if (tick == 3) { break; }
}
rep.cancel();
console.writeln("done");
tick 1
tick 2
tick 3
done