www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - __gshared as part of alias

reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
Is there a way to make __gshared part of an alias?

as in

enum AddrSpace : uint
{
     Private  = 0,
     Global   = 1,
     Shared   = 2,
     Constant = 3,
     Generic  = 4,
}

struct Variable(AddrSpace as, T)
{
     T val;
     alias val this;
}
alias Global(T)   = __gshared Variable!(AddrSpace.Global,   T);

Global!float bar1; // <- still thread local
Jan 11 2018
next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/11/18 11:25 PM, Nicholas Wilson wrote:
 Is there a way to make __gshared part of an alias?
No, __gshared is a storage class, not a type constructor, so it has no meaning as part of a type: __gshared int x; int y; static assert(is(typeof(x) == typeof(y)));
 as in
 
 enum AddrSpace : uint
 {
      Private  = 0,
      Global   = 1,
      Shared   = 2,
      Constant = 3,
      Generic  = 4,
 }
 
 struct Variable(AddrSpace as, T)
 {
      T val;
      alias val this;
 }
 alias Global(T)   = __gshared Variable!(AddrSpace.Global,   T);
dmd famously doesn't complain about attributes that do nothing, as in this case. -Steve
Jan 16 2018
parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Wednesday, 17 January 2018 at 02:37:07 UTC, Steven 
Schveighoffer wrote:
 On 1/11/18 11:25 PM, Nicholas Wilson wrote:
 Is there a way to make __gshared part of an alias?
No, __gshared is a storage class, not a type constructor, so it has no meaning as part of a type: __gshared int x; int y; static assert(is(typeof(x) == typeof(y)));
 as in
 
 enum AddrSpace : uint
 {
      Private  = 0,
      Global   = 1,
      Shared   = 2,
      Constant = 3,
      Generic  = 4,
 }
 
 struct Variable(AddrSpace as, T)
 {
      T val;
      alias val this;
 }
 alias Global(T)   = __gshared Variable!(AddrSpace.Global,   T);
dmd famously doesn't complain about attributes that do nothing, as in this case. -Steve
I kluged this into place in LDC https://github.com/ldc-developers/ldc/pull/2509/commits/7cf6f417f95a5bffa4b18f2d8b132ca8f0e900d3#diff-33d7d08455db33f1182e3936fd2ba3f9R896
Jan 16 2018
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Wednesday, January 17, 2018 07:30:30 Nicholas Wilson via Digitalmars-d-
learn wrote:
 On Wednesday, 17 January 2018 at 02:37:07 UTC, Steven

 Schveighoffer wrote:
 On 1/11/18 11:25 PM, Nicholas Wilson wrote:
 Is there a way to make __gshared part of an alias?
No, __gshared is a storage class, not a type constructor, so it has no meaning as part of a type: __gshared int x; int y; static assert(is(typeof(x) == typeof(y)));
 as in

 enum AddrSpace : uint
 {

      Private  = 0,
      Global   = 1,
      Shared   = 2,
      Constant = 3,
      Generic  = 4,

 }

 struct Variable(AddrSpace as, T)
 {

      T val;
      alias val this;

 }
 alias Global(T)   = __gshared Variable!(AddrSpace.Global,   T);
dmd famously doesn't complain about attributes that do nothing, as in this case. -Steve
I kluged this into place in LDC https://github.com/ldc-developers/ldc/pull/2509/commits/7cf6f417f95a5bffa4 b18f2d8b132ca8f0e900d3#diff-33d7d08455db33f1182e3936fd2ba3f9R896
I don't know what you're doing, and maybe __gshared is the appropriate solution for what you're trying to do, but in general, if you're not trying to bind to a C global variable, you should be using shared, and using __gshared is risking bugs precisely because it is not considered part of the type and does not prevent you from using it a thread-local context. The compiler will treat it as thread-local, risking subtle bugs that shared would catch. - Jonathan M Davis
Jan 16 2018
parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Wednesday, 17 January 2018 at 07:53:24 UTC, Jonathan M Davis 
wrote:
 I don't know what you're doing, and maybe __gshared is the 
 appropriate solution for what you're trying to do, but in 
 general, if you're not trying to bind to a C global variable, 
 you should be using shared, and using __gshared is risking bugs 
 precisely because it is not considered part of the type and 
 does not prevent you from using it a thread-local context. The 
 compiler will treat it as thread-local, risking subtle bugs 
 that shared would catch.

 - Jonathan M Davis
I was under the impression that with shared you have to either a) atomically load it or b) cast away shared before loading it. As explained in https://github.com/ldc-developers/druntime/pull/114#discussion_r161472745 that would very much add boilerplate to its most frequent use case.
Jan 17 2018
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Wednesday, January 17, 2018 10:44:24 Nicholas Wilson via Digitalmars-d-
learn wrote:
 On Wednesday, 17 January 2018 at 07:53:24 UTC, Jonathan M Davis

 wrote:
 I don't know what you're doing, and maybe __gshared is the
 appropriate solution for what you're trying to do, but in
 general, if you're not trying to bind to a C global variable,
 you should be using shared, and using __gshared is risking bugs
 precisely because it is not considered part of the type and
 does not prevent you from using it a thread-local context. The
 compiler will treat it as thread-local, risking subtle bugs
 that shared would catch.

 - Jonathan M Davis
I was under the impression that with shared you have to either a) atomically load it or b) cast away shared before loading it.
Normally, what you'd do is either use core.atomic, or you would lock a mutex (or used a synchronized block) to protect access to the object, cast away shared to do whatever you need to do, then make sure that no thread-local references to the data exist, and release the lock. e.g. synchronized(mutex) { auto nonShared = cast()mySharedObject; // do stuff to nonShared // ... // no other references to nonShared should exist here } // lock now freed If you don't care about synchronization across threads, then you can simply cast away shared to mutate the object without bother with the locks, but you do so with the knowledge that the object is not being protected against accesses from multiple threads at the same time. How much that matters depends on the type of object and what you're doing.
 As explained in
 https://github.com/ldc-developers/druntime/pull/114#discussion_r161472745
 that would very much add boilerplate to its most frequent use case.
You may have a use case where it makes sense to use __gshared, but you need to remember that the compiler is going to assume that an object that isn't marked as shared is thread-local, and it could do optimizations based on that fact. So, you're running a definite risk any time that you use __gshared. I would guess (but don't know) that that would primarily mean risking the compiler assuming that the value hasn't updated when it actually has, and if that doesn't matter in your case, you may be fine, but I don't know what optimizations the compiler really does based on TLS right now, and it could change over time. And as the compiler improves, odds are that it's only going to become riskier to use __gshared for anything other than a C global. So, in general, while it can get a bit annoying to use shared because of the need for casts, it's almost always better to use shared and not __gshared. If you were using a D class or struct rather than a float, I would _definitely_ say that __gshared was a huge mistake, but if you're using a float, and you don't care whether its value is up-to-date or not (or half-written if that's a risk on whatever architecture you're dealing with), then you may be fine. But __gshared should always be chosen with extreme caution. Unfortunately however, the extra casts and whatnot that you typically need to use with shared often does seem to cause folks to use __gshared instead and risk subtle bugs, because they just want the compiler to shut up and program like they were in C/C++ and weren't using TLS everywhere. - Jonathan M Davis
Jan 17 2018
prev sibling parent reply Johan Engelen <j j.nl> writes:
On Friday, 12 January 2018 at 04:25:25 UTC, Nicholas Wilson wrote:
 Is there a way to make __gshared part of an alias?
Hi Nick, how about this? ``` struct GSharedVariable(AddrSpace as, T) { static __gshared T val; alias val this; } alias Global(T) = GSharedVariable!(AddrSpace.Global, T); Global!float bar1; // __gshared ``` -Johan
Jan 17 2018
parent reply kinke <noone nowhere.com> writes:
On Wednesday, 17 January 2018 at 22:01:57 UTC, Johan Engelen 
wrote:
 ```
 struct GSharedVariable(AddrSpace as, T)
 {
     static __gshared T val;
     alias val this;
 }
 alias Global(T)   = GSharedVariable!(AddrSpace.Global,   T);

 Global!float bar1; // __gshared
 ```
Only 1 value per T though. ;)
Jan 17 2018
parent Johan Engelen <j j.nl> writes:
On Wednesday, 17 January 2018 at 22:56:09 UTC, kinke wrote:
 On Wednesday, 17 January 2018 at 22:01:57 UTC, Johan Engelen 
 wrote:
 ```
 struct GSharedVariable(AddrSpace as, T)
 {
     static __gshared T val;
     alias val this;
 }
 alias Global(T)   = GSharedVariable!(AddrSpace.Global,   T);

 Global!float bar1; // __gshared
 ```
Only 1 value per T though. ;)
Ah, haha indeed, I meant without the "static", but __gshared is always "static". ``` alias Global(T) = shared Variable!(AddrSpace.Global, T); ``` seems to work. https://godbolt.org/g/iDbRX7 -Johan
Jan 18 2018