| |
| Posted by Jonathan M Davis in reply to Andy Valencia | PermalinkReply |
|
Jonathan M Davis
Posted in reply to Andy Valencia
| On Friday, May 31, 2024 6:28:27 PM MDT Andy Valencia via Digitalmars-d-learn wrote:
> On Friday, 31 May 2024 at 16:59:08 UTC, Jonathan M Davis wrote:
>
> Speaking as an old kernel engineer for the Sequent multiprocessor product line, this is all very comfortable to me. I'm very glad that D has a suitable selection of spinlocks, process semaphores, and memory atomic operations. I can work with this!
The way that D handles all of this is at its core the same as C/C++. The main difference is that the type system assumes that anything that isn't marked as shared or immutable is thread-local and can do optimizations based on that (though I'm not sure that that actually happens in practice right now). And in turn, you're supposed to get errors when you do stuff with a shared object which isn't guaranteed to be thread-safe (though not all of those checks are enabled by default at the moment).
The result of this is supposed to be that the portions of your code which are operating on shared data are clearly segregated, whereas in C/C++, the type system doesn't give you any way of knowing what's actively being shared across threads. So, in principle, you're writing essentially what you want have written in C/C++, but the type system is helping you catch when you screw it up.
The annoying part is that because the compiler can't know when it's actually thread-safe to access shared data (e.g. it has no clue when the programm associates a mutex with a set of data), you have to use explicit casts to thread-local to then be able to operate on the data when it is thread-safe (unless the type is designed to be used as shared, in which case, it's doing any necessary casting internally), whereas in C/C++, since the type system doesn't know or care about thread safety, it'll just let you access data whether it's properly protected or not.
So, some folks get annoyed by the necessary casting, but in theory, it's the type system helping to minimize the risk of you shooting yourself in the foot. The idioms involved are basically the same as those used in C/C++ though, so anyone who understands those should be able to write thread-safe code in D fairly easily once they understand how shared works.
> > In any case, you can freely cast between thread-local and shared. It's just that you need to be sure that when you do that, you're not violating the type system by having a thread-local reference to shared data access that shared data without first protecting it with a mutex.
>
> That was the trick for me; TLS implied to me that an implementation would be free to arrange that the address of a variable in one thread's TLS would not necessarily be accessible from another thread. Now I'm clearer on the usage of the term WRT the D runtime. All good.
If you have a module-level or static variable that isn't shared or immutable, then each thread will get its own copy. So, those _might_ end up in TLS (I'm not sure if they are right now or not), but if you're just creating stuff on the fly, none of it is actually in TLS. And it's very common when dealing with shared or immutable data to create it first as thread-local and then cast it, since you know that it's not actually shared across threads at that point, and it's easier to construct that way. If we did want to start using TLS all over the place, then the casts would have to take that into account somehow, but I don't expect that that will happen.
- Jonathan M Davis
|