Thread overview
Ensuring allocation isn't thread-local?
Jan 22, 2022
Jaime
Jan 22, 2022
Adam D Ruppe
Jan 22, 2022
Jaime
January 22, 2022

Howdy.

How do I make sure data isn't allocated thread-local, if I also want to immediately use it in a thread-local way, because, for instance, I happen to already possess its intended mutex, which was allocated before it?

Is this sufficient? Also, is it even something to worry about?

// for classes
cast(T) new shared(T)(...)
// otherwise
cast(T*) new shared(T)(...)

For example, this is the full relevant excerpt of my WIP, untested code so far:

private struct Message {
    ulong sender;
    Variant payload;
}

private struct MessageQueue {
    DList!Message* data;
    Mutex mutex;
    Condition enqueued; // <-- Should fire on insertion.
}

// A queue for each recipient thread.
private shared(MessageQueue[ulong]) messageTable;
private Mutex tableMutex; // <-- Protects messageTable.

/*
This function should only be called by a thread holding tableMutex.
We don't acquire tableMutex in the function itself
because maybe the caller wants to do something else with it too.
*/
private ref MessageQueue getQueue(ulong recipient) {
    auto nsMessageTable = cast(MessageTable[ulong]*) &messageTable;
    MessageQueue* qptr = recipient in *nsMessageTable;
    if (qptr is null) {
        auto newMutex = cast(Mutex) new shared(Mutex);
        qptr = &((*nsMessageTable)[recipient] = MessageQueue(
            /*
            This is the part where I instantiate stuff as shared
            and then immediately cast away sharing
            because we're already holding tableMutex.
            */
            cast(DList!Message*) new shared(DList!Message),
            newMutex,
            cast(Condition) new shared(Condition)(newMutex)
        ));
    }
    return *qptr;
}

(I know it's probably not a good idea to try to implement an alternative to std.concurrency, and I should just use std.concurrency instead, but I have a good reason, and that reason is hands-on learning.)

Anyway, yeah, to reiterate: do I have the right idea here? That is:
A) Do I need to worry about data being / not being in thread-local storage?
B) If so, how do I make sure it's not there? Will my approach so far suffice?
C) If not, what's a better way?

Thanks in advance for any guidance.

January 22, 2022
On Saturday, 22 January 2022 at 18:55:30 UTC, Jaime wrote:
> A) Do I need to worry about data being / not being in thread-local storage?

No. Anything allocated with `new` is not thread local... and even if it was, you can send the pointer to other threads anyway.

The only things in thread local storage are the direct values in the non-shared global variables. What they actually point to is just generally on the main heap just like anything else.
January 22, 2022
On Saturday, 22 January 2022 at 19:06:38 UTC, Adam D Ruppe wrote:
>
> No. Anything allocated with `new` is not thread local... and even if it was, you can send the pointer to other threads anyway.
>
> The only things in thread local storage are the direct values in the non-shared global variables. What they actually point to is just generally on the main heap just like anything else.

Thanks for the response. Good to know.