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.