www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to initialize a globle variable nicely and properly?

reply Heromyth <bitworld qq.com> writes:
We have a module including many globle variables which are needed 
to be initialized firstly in "shared static this() {}", see here 
https://github.com/huntlabs/hunt/blob/master/source/hunt/time/Init.d.

The problem is that these variables are not always initialized 
firstly when are referenced by some others moudles in "static 
this() {}". Here is a demo to illustrate it.

//////////////////
// module A
//////////////////
module test.A;

import std.stdio;
import core.thread;
import core.time;

class A {
     __gshared int sharedField;

     shared static this() {
         writeln("running A in shared static this(), 
sharedField=", sharedField);

         Thread th = new Thread(() {  });
         th.start();

         Thread.sleep(100.msecs);
         sharedField = 2;
         writeln("running A done in shared static this(), 
sharedField=", sharedField);
     }

     static this() {
         writeln("running A in static this(), sharedField=", 
sharedField);
     }
}

//////////////////
// module B
//////////////////
module test.B;

import test.A;
import std.stdio;
import core.thread;

shared static this() {
     writeln("running in shared static this() from B");
}

class B {
     shared static this() {
         writeln("running B in shared static this(), 
sharedField=", A.sharedField);
     }

     static this() {
         // bug is here
         writeln("running B in static this(), sharedField=", 
A.sharedField);
     }
}

//////////////////
// module main
//////////////////
import std.stdio;

import test.A;
import core.thread;

void main()
{
	writeln("running in main.");
}

//////////////////
// output
//////////////////
Running ./demo
running A in shared static this(), sharedField=0
running A in static this(), sharedField=0
running B in static this(), sharedField=0  // bug is here
running A done in shared static this(), sharedField=2
running in shared static this() from B
running B in shared static this(), sharedField=2
running A in static this(), sharedField=2
running B in static this(), sharedField=2
running main.


====================
You can see the sharedField is 0 in B's static this() at first. 
If Thread is disabled to run in shared static this(), this 
problem seems to be fixed.

Some related bugs:
1) https://issues.dlang.org/show_bug.cgi?id=6114
2) https://issues.dlang.org/show_bug.cgi?id=4923
Dec 14 2018
next sibling parent Rubn <where is.this> writes:
On Saturday, 15 December 2018 at 02:54:55 UTC, Heromyth wrote:
 We have a module including many globle variables which are 
 needed to be initialized firstly in "shared static this() {}", 
 see here 
 https://github.com/huntlabs/hunt/blob/master/source/hunt/time/Init.d.

 The problem is that these variables are not always initialized 
 firstly when are referenced by some others moudles in "static 
 this() {}". Here is a demo to illustrate it.

 //////////////////
 // module A
 //////////////////
 module test.A;

 import std.stdio;
 import core.thread;
 import core.time;

 class A {
     __gshared int sharedField;

     shared static this() {
         writeln("running A in shared static this(), 
 sharedField=", sharedField);

         Thread th = new Thread(() {  });
         th.start();

         Thread.sleep(100.msecs);
         sharedField = 2;
         writeln("running A done in shared static this(), 
 sharedField=", sharedField);
     }

     static this() {
         writeln("running A in static this(), sharedField=", 
 sharedField);
     }
 }

 //////////////////
 // module B
 //////////////////
 module test.B;

 import test.A;
 import std.stdio;
 import core.thread;

 shared static this() {
     writeln("running in shared static this() from B");
 }

 class B {
     shared static this() {
         writeln("running B in shared static this(), 
 sharedField=", A.sharedField);
     }

     static this() {
         // bug is here
         writeln("running B in static this(), sharedField=", 
 A.sharedField);
     }
 }

 //////////////////
 // module main
 //////////////////
 import std.stdio;

 import test.A;
 import core.thread;

 void main()
 {
 	writeln("running in main.");
 }

 //////////////////
 // output
 //////////////////
 Running ./demo
 running A in shared static this(), sharedField=0
 running A in static this(), sharedField=0
 running B in static this(), sharedField=0  // bug is here
 running A done in shared static this(), sharedField=2
 running in shared static this() from B
 running B in shared static this(), sharedField=2
 running A in static this(), sharedField=2
 running B in static this(), sharedField=2
 running main.


 ====================
 You can see the sharedField is 0 in B's static this() at first. 
 If Thread is disabled to run in shared static this(), this 
 problem seems to be fixed.

 Some related bugs:
 1) https://issues.dlang.org/show_bug.cgi?id=6114
 2) https://issues.dlang.org/show_bug.cgi?id=4923
The problem here is that you are creating a new thread in the `shared static this()`. shared static this() { writeln("running A in shared static this(), sharedField=", sharedField); Thread th = new Thread(() { }); // Calls `static this()` including B's `static this()` th.start(); Thread.sleep(100.msecs); sharedField = 2; writeln("running A done in shared static this(), sharedField=", sharedField); } static this() { writeln("running A in static this(), sharedField=", sharedField); } Creating a new thread causes those thread's constructor `static this()` to be called. You need to create your threads somewhere else or have the values be initialized before the threads are created.
Dec 14 2018
prev sibling parent reply Neia Neutuladh <neia ikeran.org> writes:
On Sat, 15 Dec 2018 02:54:55 +0000, Heromyth wrote:
      shared static this() {
          writeln("running A in shared static this(),
 sharedField=", sharedField);
 
          Thread th = new Thread(() {  });
          th.start();
When you start a D thread, thread-local static constructors get run. So don't start threads until your shared static constructors finish. If I encountered something like this, I would set up a queue of actions to be run at the start of main() and fill them with static constructors. Instead of this static constructor creating a thread, it would enqueue a delegate that starts the thread.
Dec 14 2018
parent reply Heromyth <bitworld qq.com> writes:
On Saturday, 15 December 2018 at 03:48:15 UTC, Neia Neutuladh 
wrote:
 On Sat, 15 Dec 2018 02:54:55 +0000, Heromyth wrote:
      shared static this() {
          writeln("running A in shared static this(),
 sharedField=", sharedField);
 
          Thread th = new Thread(() {  });
          th.start();
When you start a D thread, thread-local static constructors get run. So don't start threads until your shared static constructors finish. If I encountered something like this, I would set up a queue of actions to be run at the start of main() and fill them with static constructors. Instead of this static constructor creating a thread, it would enqueue a delegate that starts the thread.
Yes, it's very dangerous to create a new thread in shared static this(). For a big project, it sometimes hard to identify this problem. Maybe, the compiler should do something for this, should it?
Dec 15 2018
parent Neia Neutuladh <neia ikeran.org> writes:
On Sat, 15 Dec 2018 13:49:03 +0000, Heromyth wrote:
 Yes, it's very dangerous to create a new thread in shared static this().
 For a big project, it sometimes hard to identify this problem. Maybe,
 the compiler should do something for this, should it?
The runtime, more likely. There are plenty of problems in this vein that the compiler can't detect, but the runtime should be able to detect all of them. Filed https://issues.dlang.org/show_bug.cgi?id=19492
Dec 15 2018