Threading challenge: calculate fib(45) while spinning

Steven Schveighoffer schveiguy at gmail.com
Fri Oct 15 13:52:19 UTC 2021


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


More information about the Digitalmars-d-learn mailing list