On 10/14/21 11:35 PM, jfondren wrote:
The book, "The Go Programming Language" has this simple goroutine example:```go func main() { go spinner(100 * time.Millisecond) const n = 45 fibN := fib(n) // slow fmt.Printf("\rFibonacci(%d) = %d\n", n, fibN) } func spinner(delay time.Duration) { for { for _, r := range `-\|/` { fmt.Printf("\r%c", r) time.Sleep(delay) } } } func fib(x int) int { if x < 2 { return x } return fib(x-1) + fib(x-2) } ``` Attempt #1, with std.concurrency: ```d import std.concurrency : spawn; import core.thread : Thread; import std.stdio : writefln, writef, stdout; import std.datetime : msecs, Duration; void main() @safe { (() @trusted { spawn(&spinner, 100.msecs); })(); const n = 45; const fibN = fib(n); // slow writefln!"\rFibonacci(%d) = %d"(n, fibN); } void spinner(Duration delay) @safe { (() @trusted { Thread.getThis.isDaemon(true); })(); while (true) { foreach (char c; `-\|/`) { writef!"\r%c"(c); (() @trusted { stdout.flush; })(); (() @trusted { Thread.sleep(delay); })(); } } } int fib(int x) pure @safe @nogc { if (x < 2) return x; return fib(x - 1) + fib(x - 2); } ``` This version has two problems:1. a race condition with `isDaemon`: if `main()` ends before `isDaemon(true)` is called, then the program never ends because the kill-non-daemon-threads module destructor is called while the new thread isn't a daemon thread.
You can also just spawn a thread directly with `Thread`, which I believe allows you to set the daemon-ness from `main`.
2. it crashes about 10% of the time on exit (in dmd, gdc, and ldc). valgrind on a gdc build complains about "Conditional jump or move depends on uninitialised value(s)" early on.
The crash is likely because you are using D i/o utilities, and the runtime is shut down. Technically it shouldn't cause a problem, but possibly there are things that are needed deep inside `writef`.
If you switch to `printf`, it will probably work. -Steve
