Threading challenge: calculate fib(45) while spinning
Ali Çehreli
acehreli at yahoo.com
Fri Oct 15 14:01:43 UTC 2021
On 10/14/21 8:54 PM, Ali Çehreli wrote:
> writefln!"\rFibonacci(%d) = %d"(n, fibN);
That '\r' bothered me because the actual work needs to know what the
spinner is doing to clear its remaining character.
> receiveTimeout(delay,
> (OwnerTerminated msg) {
And there is a race condition because the spinner can print an extra
character by the time it receives the OwnerTerminated message. (You can
observe this by adding e.g. Thread.sleep(300.msecs) after the
"\rFibonnacci..." line above.)
So, I improved it by removing both of those concerns as well as adding
the following:
- An optional message when spinning (it can be further improved because
there is an extra space character if the message is empty)
- A withSpinner() function to work with any delegate
The only requirement is that the delegate should not output to stdout if
we want a clean output.
import std.stdio : stdout, writef, writefln;
import std.concurrency : receiveTimeout, send, spawn;
import std.traits : ReturnType;
import core.thread : Duration, msecs, Thread;
import std.range : cycle, repeat, walkLength;
import std.format : format;
void main() {
enum n = 45;
int fibN; // Left mutable not to complicate the example
withSpinner({
fibN = fib(n); // slow
},
format!"Calculating fib(%s)"(n));
writefln!"Fibonacci(%d) = %d"(n, fibN);
}
// The delegate 'dg' should not output to stdout.
void withSpinner(Dg)(Dg dg,
string message = null,
Duration delay = 100.msecs) {
shared(bool) spinnerDone = false;
auto s = spawn(&spinner, message, delay, &spinnerDone);
// Do work while spinning
dg();
// Tell the spinner to stop (the value does not matter)
s.send(0x0FF);
// Busy(ish) wait until the spinner is done
while (!spinnerDone) {
Thread.yield();
}
}
void spinner(string message,
Duration delay,
shared(bool) * done) {
foreach (c; `-\|/`.cycle) {
if (receiveTimeout(delay, (int _) {})) {
// Stop request received
// Clear the spinning message
writef("\r%s \r", " ".repeat(walkLength(message)));
// Tell the user we are done
*done = true;
return;
}
writef!"\r%s %c"(message, c);
stdout.flush();
}
}
auto fib(int x) {
if (x < 2) {
return x;
}
return fib(x-1) + fib(x-2);
}
Ali
More information about the Digitalmars-d-learn
mailing list