how does 'shared' affect member variables?

bitwise via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sat May 9 15:14:07 PDT 2015


On Sat, 09 May 2015 15:59:57 -0400, tcak <tcak at gmail.com> wrote:
> If a variable/class/struct etc is not shared, for variables and struct,  
> you find their initial value. For class, you get null.
>
> For first timers (I started using shared keyword more than 2 years ago),  
> do not forget that: a shared method is all about saying that this method  
> is defined for shared object. So, do not get confused. It happened to me  
> a lot.
>
> Bad part of shared is that, you will be repeating it again, and again,  
> and again, and again, everywhere. So, try to be patient if you are going  
> to be using it for a long time.
>
> Stupidly, shared variables' value cannot be increased/decreased  
> directly. Compiler says it is deprecated, and tells me to use  
> core.atomic.atomicop. You will see this as well. Hey compiler! I know  
> 100% that no other thing will be touching this variable.


using the SpinLock and LockGuard from my code above, I created a working  
test case. It works as expected, with no shared keyword on anything. The  
variable "App._instance" is __gshared, but that's about all.

///////////////////////////
import spinlock;
import std.stdio;
import std.concurrency;
import std.container;
import core.thread;

class App
{
     SpinLock _lock;
     Array!(void delegate()) _actions;

     __gshared App _instance = null;

     this() {
         assert(!_instance);
         _instance = this;
     }

     ~this() {
         _instance = null;
     }

     @property public static App instance() {
         return _instance;
     }

     void run(void delegate() dg) {
         auto lk = LockGuard!SpinLock(_lock);
         _actions.insertBack(dg);
         writeln("queued delegate");
     }

     void update()
     {
         writeln("updating");

         auto lk = LockGuard!SpinLock(_lock);

         foreach(act; _actions)
             act();

         _actions.clear();
     }
}

void WorkerThread()
{
     writeln("started worker, going to sleep");

     Thread.sleep(500.msecs);

     App.instance.run({
             writeln("running delegate queued from thread");
         });
}

void main()
{
     App app = new App();

     Thread workerThread = new Thread(&WorkerThread).start();

     int ms = 0;

     while(ms < 1000)
     {
         app.update();
         Thread.sleep(100.msecs);
         ms += 100;
     }

     workerThread.join();
}

//////////////

OUTPUT:

updating
started worker, going to sleep
updating
updating
updating
updating
queued delegate
updating
running delegate queued from thread
updating
updating
updating
updating

//////////////

No null references or 'init' values. A little confused now, but at least  
it works.

Finally, I tested to see if the lock was actually working:

void WorkerThread()
{
     writeln("worker aquiring lock");
     App.instance._lock.lock();
     writeln("worker aquired lock");
     App.instance._lock.unlock();
}

void main()
{
     App app = new App();

     writeln("main locked");
     App.instance._lock.lock();

     Thread workerThread = new Thread(&WorkerThread).start();

     writeln("main sleeping");
     Thread.sleep(2.seconds);
     writeln("main woke");
     App.instance._lock.unlock();
     writeln("main unlocked");

     workerThread.join();
}

As expected, output was:

main locked
main sleeping
worker aquiring lock
main woke
main unlocked
worker aquired lock



And no 'shared' in sight. So now I'm confused as to when it has the affect  
that you were describing with null/init.

   Bit


More information about the Digitalmars-d-learn mailing list