Bug 17543 – __gshared block modifier is ignored by static variables

Status
RESOLVED
Resolution
INVALID
Severity
normal
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2017-06-23T15:43:00Z
Last change time
2017-06-24T17:05:25Z
Assigned to
nobody
Creator
weltensturm

Comments

Comment #0 by weltensturm — 2017-06-23T15:43:38Z
DMD32 D Compiler v2.074.0 EXAMPLE: import std.stdio, std.parallelism; __gshared: void test(){ static bool set; if(!set){ set = true; writeln("set = true;"); } } void main(string[] args){ auto t = { test; }.task; t.executeInNewThread; t.spinForce; test; } OUTPUT: set = true; set = true; EXPECTED: set = true; Using __gshared bool set; results in the expected output.
Comment #1 by petar.p.kirov — 2017-06-24T16:30:49Z
All attributes (e.g. public/private, pure/nothrow/@safe/@nogc, const/shared, final, __gshared, and so on) are applied only to the scope they are declared in. As soon as you open a new scope they are effectively reset.
Comment #2 by petar.p.kirov — 2017-06-24T16:36:47Z
I'll close this bug as there's nothing specific to __gshared, but of course you're free to open a discussion on the newsgroup and to propose a way to control this. I have an idea for a DIP (D improvement proposal) on that matter, but no promises when I'll have enough time to sit down, write it down and submit it.
Comment #3 by weltensturm — 2017-06-24T16:37:37Z
This works though: import std.stdio, std.parallelism; __gshared: auto return_gshared(){ class Test { bool set; } return new Test(); } void main(){ auto obj = return_gshared(); auto t = { obj.set = true; }.task; t.executeInNewThread; t.spinForce; writeln(obj.set); }
Comment #4 by petar.p.kirov — 2017-06-24T17:00:09Z
(In reply to Robert Luger from comment #3) > This works though: > > > import std.stdio, std.parallelism; > > > __gshared: > > > auto return_gshared(){ > > class Test { > bool set; > } > > return new Test(); > > } > > > void main(){ > auto obj = return_gshared(); > auto t = { obj.set = true; }.task; > t.executeInNewThread; > t.spinForce; > writeln(obj.set); > } __gshared has no effect in the program above (e.g. commenting it out doesn't change the result). That's because the variable 'obj' of type 'Test' is shared by both the main thread and the thread on which the task is executed. One simple test to verify if a class/struct member is effectively 'static' (i.e. shared by all instances of the current thread, or all threads (if it's declared as either '__gshared' or 'static shared') is to check if: * It has the 'offsetof' property, or * If it can be accessed with the 'Type.staticMember' sytnax (which is what I think effectively http://dlang.org/phobos/std_traits#hasStaticMembery does) __gshared: auto return_gshared(){ class Test { bool set; } pragma (msg, __traits(compiles, { size_t offset = Test.set.offsetof; })); // true pragma (msg, Test.set.offsetof); // 16LU pragma (msg, __traits(compiles, { auto copyOfStaticVariable = Test.set; })); // false return new Test(); }
Comment #5 by petar.p.kirov — 2017-06-24T17:05:25Z
Just a tip: it's useful to encode such assumptions about how your code works by using 'static assert'. For example: class Test { int instanceMember; __gshared int globalGSharedMember; static int threadLocalStaticMember; static int globalSharedMember; } import std.traits : hasStaticMember; static assert (!hasStaticMember!(Test, "instanceMember")); static assert ( hasStaticMember!(Test, "globalGSharedMember")); static assert ( hasStaticMember!(Test, "threadLocalStaticMember")); static assert ( hasStaticMember!(Test, "globalSharedMember"));