On Tuesday, 10 March 2020 at 20:03:21 UTC, mark wrote:
I've managed to make a cut-down version that's < 170 LOC.
It needs to be run on Debian or a Debian-based Linux (e.g., Ubuntu).

Hopefully this will help someone understand and be able to help!

This took some time figuring out. Turns out, std.concurrency.spawn won't take a delegate as its callable argument. There are sensible reasons for this - delegates have a context that is not guaranteed to be immutable, so allowing delegate callables could lead to mutable aliasing. I've filed an issue to improve documentation and error messages: https://issues.dlang.org/show_bug.cgi?id=20665

However, knowing that some things are impossible do not necessarily help us figure out what we can do to fix the problem, and the good news is, the problems can be fixed. Since the problem is we're giving a delegate where the API expects a function, we can simply turn it into a function. In the code you've given, that means making readPackageFile and readPackageLine static. This make spawn() run as it should.

In addition, there's a problem with this line in receive():

    (DoneMessage) { jobs--; }

That looks sensible, but since DoneMessage doesn't have a name, it is parsed as a templated function taking one argument of unspecified type and called DoneMessage. For some reason, templates passed as function arguments show up in compiler output as 'void', giving this weird error message:

template std.concurrency.receive cannot deduce function from argument types !()(void delegate(Deb deb) pure nothrow @safe, void)

The solution here is to simply give DoneMessage a name:

    (DoneMessage d) { jobs--; }

With those changes, things at least compile. Now it's up to you to ensure the semantics are correct. :)

One last thing: you're passing parentTid around, and that's not actually necessary - std.concurrency.ownerTid does the exact same thing, and is available even if not explicitly passed anywhere.

--
  Simen

Reply via email to