Very limited shared promotion
Ola Fosheim Grøstad
ola.fosheim.grostad at gmail.com
Wed Jun 19 07:29:21 UTC 2019
On Tuesday, 18 June 2019 at 22:30:28 UTC, Jonathan M Davis wrote:
> Storing a reference to a scope object in @trusted code would
> violate what scope is supposed to guarantee.
Ok, so you are only considering stack allocated objects?
My question is more like this. If I use GC throughout, then I
might write a @trusted framework with that in mind, and take
references wherever it makes sense. No problem, right?
However, when someone pass a shared (still GC managed) object
that has been temporarily "unshared", and pass it into that to
the framework... then it will break badly.
So, from a memory-management perspective the framework is sound,
but not from a thread safety point of view.
Is that right?
> but if your @trusted code does anything which violates the
> guarantees that @safe is supposed to make, then the programmer
> who verified that it was okay to mark it as @trusted screwed up.
But only if it was vetted with "shared" in mind, because if it
was vetted for safe release of memory, and you use GC or
reference counting, then it was perfectly OK, but still breaks
for "unshared" shared?
Maybe this will demand too much from the person doing the vetting
of generic code, to both get it right for memory management and
thread safety?
> @safe really only deals with memory safety, not thread-safety.
> Converting between shared and thread-local does require a cast,
> which is @trusted, because you're basically stepping outside of
> the type system.
Ok, but what if you didn't step outside the type system? What
would D need to cover this within the type system?
> What Manu is proposing is a scenario where the type system is
> able to guarantee that no references to the variable escape and
> that based on that assumption, temporarily converting to shared
> wouldn't violate the guarantees that come with the object
> actually being thread-local.
That sounds reasonable.
> scope object actually escaped. If the programmer screws that
> up, then the implicit conversion to shared will have violated
> the guarantees that are supposed to go with the object being
> thread-local, and unlike now, the point of the conversion
Yes, but this is where a more elaborate type system would help. I
haven't mentioned Pony
( https://www.ponylang.io/ ) in a while, so to recap:
Pony tracks whether an object-reference is unique among other
things.
https://tutorial.ponylang.io/reference-capabilities/reference-capabilities.html
So, that might be worth considering.
I don't think it has to be tedious if you use auto/type
deduction/flow typing.
> On the surface, what Manu is proposing _seems_ sound (assuming
> that any @trusted code involved is vetted properly), but as
> Walter points out, it's really easy to screw up threading stuff.
Yes, that is true, and "shared" isn't even the most challenging
problem. The real challenge is to prove that starvation/deadlock
cannot happen in a complex system.
(which of course is a good reason to avoid complex systems in the
first place)
> Also, normally, shared objects either deal with their
> thread-safety stuff internally (e.g. by having an internal
> mutex that locks appropriately when accessing the object's
> members),
Only works in very simple scenarios, you often need to grab
multiple resources at once. Also, fine granularity locks tend to
come with high performance penalties.
So, I think one should exclude that solution and focus on the
general case. Single object sync isn't really a solution that
will convince anyone that a language has nailed concurrency…
> or they require that you deal with the thread synchronization
> stuff explicitly (e.g. by directly dealing with the mutex
> whenever the shared object needs to be accessed).
Yes, I agree if you change "object" to "objects".
> Having a function that's expecting a shared variable be given a
> thread-local one seems off to me.
Well, if you use reference-capabilites in the vein of Pony then I
think it follows naturally.
And that appears to be what D is trying to do with "shared", but
without the precision needed to solve issues that seems
reasonable to people working in the trenches (like Manu).
> shared without letting it escape, but I'm still inclined to
> think that the conversion should be vetted by the programmer
> rather than being considered okay and done implicitly just
> because scope is involved.
But, to play the devil's advocate:
If the compiler doesn't provide strong semantic passes for
"shared" why do you then need "shared" to be part of the type
system? Why couldn't you then just let "shared" be implemented
as a template within a templated pointer framework?
For "shared" to be justified as a language feature it has to
provide something that cannot be done within the meta-programming
capabilities of the language.
For "const" it is obvious, the transitive const cannot be done
within the meta-programming capabilities of the language (or
maybe it can, I am making an assumption).
But how does "shared" justify itself? Is it all about
@safe/@trusted/@system?
In that case, maybe those capabilities could be available as
meta-programming mechanisms so that "shared" could be done as a
library feature.
Or rather, what prevents "shared" from being a library feature
(assuming all pointers are templates).
> Regardless, as discussed at dconf this year, D's memory model
> and the exact semantics of shared really need to be properly
> locked down before we start making changes like this.
Indeed.
> but not all of the details have been properly ironed out yet,
> and the devil is in the details.
Certainly.
I would also argue that whatever you land on for managing a
resource like memory, also should be considered to be extended to
manage a "resource" like read/write access to shared objects.
Ola.
More information about the Digitalmars-d
mailing list