= Solution
Maintain the latest five <temperature> readings in a <circular buffer>, together with their running <sum>. The following <C programming language> code spells out the <message passing> interface rather than assuming a particular library: `send(dst,&m)` is a blocking <synchronous message passing> send; `receive(src,&m)` receives from the specified sender or `ANY` and returns the sender's identity; `sendrec(dst,&m)` atomically sends the request and waits for that sender's reply in the same message object. Successful, reliable operations are assumed. Message contents are copied by the interface.
``
enum { ANY = -1, TIMER = 1, TEMP = 2 };
enum { PULSE, PING, REQUEST, REPLY };
typedef struct {
int type;
int period_ms;
double value;
} Message;
extern void send(int dst, const Message *m);
extern int receive(int src, Message *m);
extern void sendrec(int dst, Message *m);
void smooth(void) {
double history[5] = {0};
double sum = 0;
int count = 0, next = 0;
Message m = { .type = PULSE, .period_ms = 1000 };
send(TIMER, &m); /* subscribe once */
for (;;) {
int sender = receive(count < 5 ? TIMER : ANY, &m);
if (sender == TIMER && m.type == PING) {
Message t = { .type = REQUEST };
sendrec(TEMP, &t); /* matching REPLY contains t.value */
if (count == 5)
sum -= history[next];
else
++count;
history[next] = t.value;
sum += t.value;
next = (next + 1) % 5;
} else if (count == 5 && m.type == REQUEST) {
Message answer = { .type = REPLY, .value = sum / 5.0 };
send(sender, &answer);
}
}
}
``
Before the fifth reading, selective reception from `TIMER` prevents premature client requests from being accepted. Such clients wait at their synchronous sends; they are not given a partial <arithmetic mean>. Thereafter the <operating-system process> receives both timer messages and client requests. Each accepted `PING` initiates one measurement; each accepted client request returns the <arithmetic mean> of the five most recently completed measurements, without initiating another measurement or changing the <circular buffer>.
The <loop invariant> is that `count` is the number of valid readings, capped at five, `sum` is their <sum>, and `next` is the next unused slot during startup or the oldest slot afterwards. Removing the overwritten reading and adding the new one preserves this <loop invariant>. Each update and reply uses $O(1)$ <time complexity> and $O(1)$ storage, since the window length is fixed. Under timely sensor replies, timer delivery and <process scheduling>, measurements are initiated once per second. The next parts explain failures of these timing assumptions; the code does not promise one-second sampling when the <sensor> itself cannot sustain it.
Back to article page