AA vs __gshared

Jonathan M Davis newsgroup.d at jmdavisprog.com
Thu Jul 27 21:31:02 UTC 2023


On Thursday, July 27, 2023 9:57:51 AM MDT IchorDev via Digitalmars-d-learn 
wrote:
> I've been getting a lot of segfaults from using associative
> arrays recently. The faults happen seemingly at random, and from
> pretty mundane stuff like `if(auto x = y in z)` that run very
> often:
> ```
> Segmentation fault.
> #0  0x0000555555670f4a in rt.aaA.Impl.findSlotLookup(ulong, scope
> const(void*), scope const(TypeInfo)) inout ()
> #1  0x0000555555661662 in _aaInX ()
> ```
>
> I suspect that this is because they've all been placed inside
> `__ghared` structs. Are DRuntime's AAs simply incompatible with
> `__gshared`? Do they need to be marked as `shared` to prevent
> these shenanigans?

Strictly speaking, __gshared is really only intended for stuff like C
globals (which can't be shared due to name-mangling issues). Using it on
anything else can at least potentially cause problems due to the fact that
the compiler will assume that the variable is thread-local. So, I would
strongly advise against using __gshared in a case like this. In practice,
you can often get away with it, because the compiler doesn't do much in the
way of optimizing stuff based on objects being thread-local right now, but
it's definitely risking problems with the type system if you used __gshared
when you're not trying to do something like bind to a C global.

What should normally be happening is that you use shared, and then when
you've protected the object so that you know that it can only be accessed on
the current thread by the section of code that you're in (e.g. by locking a
mutex), you temporarily cast away shared to operate on the object via a
thread-local reference. Then, before exiting that section of code and
removing the protections that are preventing other threads from accessing
the object (e.g. by unlocking the mutex), you make sure that you've gotten
rid of all of the thread-local references to the object so that only the
shared reference exists. That way, you don't accidentally mutate the object
while it's not protected from access by other threads.

Now, as to what's happening in your code that's causing segfaults, the most
likely culprit would be that you're accessing the AA without actually having
done anything to prevent other threads from accessing it at the same time
(or your protections were inadequate). And because the object is being
treated as thread-local by the compiler, it would be easy to have
accidentally let a reference to it leak somewhere that wasn't being
protected by whatever mutex you're using, whereas if the AA were shared, the
only sections of code where you would have to worry about thread-local
references escaping would be in the sections of code where you've cast away
shared after locking the relevant mutex. So, similar to what happens with
@safe and @trusted, using shared allows you to limit the code that you have
to examine to find the problem.

- Jonathan M Davis





More information about the Digitalmars-d-learn mailing list