www.digitalmars.com         C & C++   DMDScript  

digitalmars.dip.ideas - Make TLS explicit

reply Dave P. <dave287091 gmail.com> writes:
A long time ago, global variables and static variables in D were 
changed to be thread local by default. I think this has proven to 
mostly be a bad idea, for a few reasons:

- Violates the “looks like C principle”: Code that looks like C 
should either behave the same as C or not compile.
- Unexpected: No other language defaults to TLS.
- Unwanted: Most of the time you don’t actually want thread local 
variables. If you want global state you either want immutability 
or synchronized access (mutexes) through something like shared. 
TLS is the exception.
- Not as safe as it looks: thread local variables still have many 
of the problems of global variables, such as having to worry 
about function re-entrancy.

So I propose to make it an error to have it be unspecified if a 
static variable is shared, __gshared, immutable or thread local. 
Additionally, add a thread_local storage class so you can 
explicitly opt into TLS for when you actually want that.

Changing this might require a new edition, but who knows.
Apr 16
next sibling parent reply Mike Shah <mshah.475 gmail.com> writes:
On Wednesday, 16 April 2025 at 22:46:32 UTC, Dave P. wrote:
 A long time ago, global variables and static variables in D 
 were changed to be thread local by default. I think this has 
 proven to mostly be a bad idea, for a few reasons:

 - Violates the “looks like C principle”: Code that looks like C 
 should either behave the same as C or not compile.
 - Unexpected: No other language defaults to TLS.
 - Unwanted: Most of the time you don’t actually want thread 
 local variables. If you want global state you either want 
 immutability or synchronized access (mutexes) through something 
 like shared. TLS is the exception.
 - Not as safe as it looks: thread local variables still have 
 many of the problems of global variables, such as having to 
 worry about function re-entrancy.

 So I propose to make it an error to have it be unspecified if a 
 static variable is shared, __gshared, immutable or thread 
 local. Additionally, add a thread_local storage class so you 
 can explicitly opt into TLS for when you actually want that.

 Changing this might require a new edition, but who knows.
I have found explicitly marking data that is meant to be shared is the right default for me (i.e., I like the thread-local default). I personally want life to be easier to write concurrent applications that are correct and avoid race conditions. I've for instance run into problems when passing data between threads -- in many cases D will prevent that if the data is not marked as shared, or otherwise global. I'm quite curious if you have a use case, perhaps a mixed codebase with C code that provides a counterexample? I understand there could otherwise probably be improvements to 'shared' qualifier otherwise. Reference on migration to shared: https://dlang.org/articles/migrate-to-shared.html Note: the -vtls switch is also quite useful for otherwise investigating code.
Apr 17
parent Dave P. <dave287091 gmail.com> writes:
On Thursday, 17 April 2025 at 19:09:49 UTC, Mike Shah wrote:
 On Wednesday, 16 April 2025 at 22:46:32 UTC, Dave P. wrote:
 [...]
I have found explicitly marking data that is meant to be shared is the right default for me (i.e., I like the thread-local default). I personally want life to be easier to write concurrent applications that are correct and avoid race conditions. I've for instance run into problems when passing data between threads -- in many cases D will prevent that if the data is not marked as shared, or otherwise global. I'm quite curious if you have a use case, perhaps a mixed codebase with C code that provides a counterexample? I understand there could otherwise probably be improvements to 'shared' qualifier otherwise.
The problem isn’t shared, it’s when you port C code to D, it is easy to forget that D has the thread local default for globals, which can be a performance issue and also just very confusing if you do ever decide to move things to threads. If it was a compile error to not specify it would be fine. You’d mark it `__gshared` while porting, with the `__gshared` acting as a FIXME list you can clean up later. Or you explicitly mark it as thread local to show you’ve actually decided one way or the other. Or you make it immutable, etc.
 Reference on migration to shared: 
 https://dlang.org/articles/migrate-to-shared.html
 Note: the -vtls switch is also quite useful for otherwise 
 investigating code.
Apr 17
prev sibling next sibling parent reply Guillaume Piolat <first.nam_e gmail.com> writes:
On Wednesday, 16 April 2025 at 22:46:32 UTC, Dave P. wrote:
 A long time ago, global variables and static variables in D 
 were changed to be thread local by default. I think this has 
 proven to mostly be a bad idea, for a few reasons:

 - Violates the “looks like C principle”: Code that looks like C 
 should either behave the same as C or not compile.
 - Unexpected: No other language defaults to TLS.
 - Unwanted: Most of the time you don’t actually want thread 
 local variables. If you want global state you either want 
 immutability or synchronized access (mutexes) through something 
 like shared. TLS is the exception.
 - Not as safe as it looks: thread local variables still have 
 many of the problems of global variables, such as having to 
 worry about function re-entrancy.

 So I propose to make it an error to have it be unspecified if a 
 static variable is shared, __gshared, immutable or thread 
 local. Additionally, add a thread_local storage class so you 
 can explicitly opt into TLS for when you actually want that.

 Changing this might require a new edition, but who knows.
+1 It really brings zero benefit to have it implicit (when did you really want that). We should finally admit to that being a mistake. If the goal was "no sharing by default", then explicit TLS keeps that goal.
Apr 19
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Saturday, April 19, 2025 6:47:31 AM MDT Guillaume Piolat via dip.ideas wrote:
 On Wednesday, 16 April 2025 at 22:46:32 UTC, Dave P. wrote:
 A long time ago, global variables and static variables in D
 were changed to be thread local by default. I think this has
 proven to mostly be a bad idea, for a few reasons:

 - Violates the “looks like C principle”: Code that looks like C
 should either behave the same as C or not compile.
 - Unexpected: No other language defaults to TLS.
 - Unwanted: Most of the time you don’t actually want thread
 local variables. If you want global state you either want
 immutability or synchronized access (mutexes) through something
 like shared. TLS is the exception.
 - Not as safe as it looks: thread local variables still have
 many of the problems of global variables, such as having to
 worry about function re-entrancy.

 So I propose to make it an error to have it be unspecified if a
 static variable is shared, __gshared, immutable or thread
 local. Additionally, add a thread_local storage class so you
 can explicitly opt into TLS for when you actually want that.

 Changing this might require a new edition, but who knows.
+1 It really brings zero benefit to have it implicit (when did you really want that). We should finally admit to that being a mistake. If the goal was "no sharing by default", then explicit TLS keeps that goal.
Not really. If anything, it gets rid of the default and then forces you to add extra attributes to types all over the place in order to be explicit. The current situation largely works extremely well, because having variables not be shared across threads is almost always what you want, and it's required for memory safety, because you can't access variables which are shared across threads in thread-safe manner without extra machinery to ensure that those reads and writes are thread-safe. I can understand there being some frustration when porting code, because the type systems of other languages like C do not encode whether something is shared across threads or not, but the fact that D has that distinction helps localize threading issues and is required for the memory safety guarantees that the language is supposed to be providing. And because very little code in general is sharing anything across threads, the amount of code that needs to encode that distinction in the types is small. So, the number of explicit attributes required is small. But if we got rid of the default and required that it be explict, then that would literally mean adding an additional attribute onto almost every time everywhere, which would be incredibly verbose. And if the argument is that static variables or module-level variables should be treated differently and require an explicit attribute which is the opposite of shared, then that would create a pretty massive inconsistency in how types are dealt with for this one corner case that's really only an issue when porting code. And in my experience, static and module-level variables are almost always thread-local just like the rest of the objects in the program. It's just specific sections of multi-threaded code that needs to worry about shared, and __gshared is really only supposed to be used when binding to C globals anyway - and the fact that __gshared is shared but typed as thread-local is actually a hole in safe, though now that we have system variables, we could fix it so that all __gshared variables are system, which would fix that problem. - Jonathan M Davis
Apr 19
prev sibling next sibling parent ryuukk_ <ryuukk.dev gmail.com> writes:
On Wednesday, 16 April 2025 at 22:46:32 UTC, Dave P. wrote:
 A long time ago, global variables and static variables in D 
 were changed to be thread local by default. I think this has 
 proven to mostly be a bad idea, for a few reasons:

 - Violates the “looks like C principle”: Code that looks like C 
 should either behave the same as C or not compile.
 - Unexpected: No other language defaults to TLS.
 - Unwanted: Most of the time you don’t actually want thread 
 local variables. If you want global state you either want 
 immutability or synchronized access (mutexes) through something 
 like shared. TLS is the exception.
 - Not as safe as it looks: thread local variables still have 
 many of the problems of global variables, such as having to 
 worry about function re-entrancy.

 So I propose to make it an error to have it be unspecified if a 
 static variable is shared, __gshared, immutable or thread 
 local. Additionally, add a thread_local storage class so you 
 can explicitly opt into TLS for when you actually want that.

 Changing this might require a new edition, but who knows.
+1 TLS usage should always be explicit, it comes with performance considerations so it should be used with care It's the rare case where i don't mind having an attribute to use, something like ` tls` (built in, no imports needed)
Apr 19
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Wednesday, 16 April 2025 at 22:46:32 UTC, Dave P. wrote:
 A long time ago, global variables and static variables in D 
 were changed to be thread local by default. I think this has 
 proven to mostly be a bad idea, for a few reasons:

 - Violates the “looks like C principle”: Code that looks like C 
 should either behave the same as C or not compile.
 - Unexpected: No other language defaults to TLS.
 - Unwanted: Most of the time you don’t actually want thread 
 local variables. If you want global state you either want 
 immutability or synchronized access (mutexes) through something 
 like shared. TLS is the exception.
I most definitely want TLS by default and to only have sharing if I explicitly say otherwise. If you end up having something that looks shared and isn't, you'll find out quickly (unless you ever only have one thread) and it'll be easily reproducible. If you neglect to prevent data races you're in for a "fun" time figuring out what's going on. TLS by default is in my opinion one of D's many wins.
Apr 21
parent Dom DiSc <dominikus scherkl.de> writes:
On Monday, 21 April 2025 at 14:00:21 UTC, Atila Neves wrote:
 TLS by default is in my opinion one of D's many wins.
+1
Apr 22