www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Static problem

reply Bob Cowdery <bob bobcowdery.plus.com> writes:
 Can someone sort out what I'm doing wrong here please.
-------------
import std.concurrency, std.stdio;
import Definitions.procNames;

class CRegistry {
    static Tid[E_PROC] TidRegistry;

    static void register(E_PROC name, Tid tid) {

        writeln(TidRegistry);
        TidRegistry[name] = tid;
    }

    static Tid getTid(E_PROC name) {

        //writeln("Entries: ", TidRegistry);
        if(name in TidRegistry) {
            writeln ("Returning ,", TidRegistry[name], " for " , name);
            return TidRegistry[name];
        }
        return thisTid();
    }
}
--------------

I register TID's like so:
CRegistry.register(E_PROC.HPSDR, hpsdr_tid);
and get them like so:
CRegistry.getTid(E_PROC.HPSDR);

If I call getTid() from any another module other than the one than set
the values, TidRegistry is empty. How do I share this registry between
modules.

Thanks
bob
Oct 07 2010
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
Bob Cowdery wrote:
  Can someone sort out what I'm doing wrong here please.
 -------------
 import std.concurrency, std.stdio;
 import Definitions.procNames;
 
 class CRegistry {
     static Tid[E_PROC] TidRegistry;
 
     static void register(E_PROC name, Tid tid) {
 
         writeln(TidRegistry);
         TidRegistry[name] = tid;
     }
 
     static Tid getTid(E_PROC name) {
 
         //writeln("Entries: ", TidRegistry);
         if(name in TidRegistry) {
             writeln ("Returning ,", TidRegistry[name], " for " , name);
             return TidRegistry[name];
         }
         return thisTid();
     }
 }
 --------------
 
 I register TID's like so:
 CRegistry.register(E_PROC.HPSDR, hpsdr_tid);
 and get them like so:
 CRegistry.getTid(E_PROC.HPSDR);
 
 If I call getTid() from any another module other than the one than set
 the values, TidRegistry is empty. How do I share this registry between
 modules.
 
 Thanks
 bob
 
Could you please post the use case as well? It should matter not from what module you make the calls, as long as those calls are from the same thread. Different threads get different copies of the registry.
Oct 07 2010
parent reply Bob Cowdery <bob bobcowdery.plus.com> writes:
 On 07/10/2010 20:33, Stanislav Blinov wrote:
 Bob Cowdery wrote:
  Can someone sort out what I'm doing wrong here please.
 -------------
 import std.concurrency, std.stdio;
 import Definitions.procNames;

 class CRegistry {
     static Tid[E_PROC] TidRegistry;

     static void register(E_PROC name, Tid tid) {

         writeln(TidRegistry);
         TidRegistry[name] = tid;
     }

     static Tid getTid(E_PROC name) {

         //writeln("Entries: ", TidRegistry);
         if(name in TidRegistry) {
             writeln ("Returning ,", TidRegistry[name], " for " , name);
             return TidRegistry[name];
         }
         return thisTid();
     }
 }
 --------------

 I register TID's like so:
 CRegistry.register(E_PROC.HPSDR, hpsdr_tid);
 and get them like so:
 CRegistry.getTid(E_PROC.HPSDR);

 If I call getTid() from any another module other than the one than set
 the values, TidRegistry is empty. How do I share this registry between
 modules.

 Thanks
 bob
Could you please post the use case as well? It should matter not from what module you make the calls, as long as those calls are from the same thread. Different threads get different copies of the registry.
I suspected that might be the case. Yes they are from separate threads. No conflict as one writes all the tids and the others only read them. What's the best way to fix that?
Oct 07 2010
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
Bob Cowdery wrote:

 Could you please post the use case as well? It should matter not from
 what module you make the calls, as long as those calls are from the
 same thread. Different threads get different copies of the registry.
I suspected that might be the case. Yes they are from separate threads. No conflict as one writes all the tids and the others only read them. What's the best way to fix that?
I wouldn't be too quick to state that there is no conflict, as associative array access/lookup is most probably not an atomic operation. What I'd propose is either: 1) Create your own lock-free associative array (yup, reinvent the wheel to introduce AA to the world of 'shared') 2) In this small case it may seem best (though mind that often such cases do grow up to the point when you still need to rethink design): Make your associative array __gshared and perform synchronization by hand, i.e. create a static Mutex (from core.sync.mutex) variable and initialize it in your CRegistry's static ctor, and then enclose all access to associative array in synchronized(mutex) {} blocks. Maybe concurrent-programming-in-D guru may propose simpler solution, but I don't see another. P.S. You can get much useful info on this topic in TDPL, the chapter on concurrency is even available for free: http://www.informit.com/articles/article.aspx?p=1609144
Oct 07 2010
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 07 Oct 2010 16:18:26 -0400, Stanislav Blinov  
<stanislav.blinov gmail.com> wrote:

 Bob Cowdery wrote:

 Could you please post the use case as well? It should matter not from
 what module you make the calls, as long as those calls are from the
 same thread. Different threads get different copies of the registry.
I suspected that might be the case. Yes they are from separate threads. No conflict as one writes all the tids and the others only read them. What's the best way to fix that?
I wouldn't be too quick to state that there is no conflict, as associative array access/lookup is most probably not an atomic operation. What I'd propose is either: 1) Create your own lock-free associative array (yup, reinvent the wheel to introduce AA to the world of 'shared') 2) In this small case it may seem best (though mind that often such cases do grow up to the point when you still need to rethink design): Make your associative array __gshared and perform synchronization by hand, i.e. create a static Mutex (from core.sync.mutex) variable and initialize it in your CRegistry's static ctor, and then enclose all access to associative array in synchronized(mutex) {} blocks. Maybe concurrent-programming-in-D guru may propose simpler solution, but I don't see another.
FWIW, the classinfo of a class is an object, and as such can be used as sort of a global lock without having to use a static constructor: synchronized(this.classinfo) { .... } -Steve
Oct 07 2010
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
Steven Schveighoffer wrote:

 What I'd propose is either:
 1) Create your own lock-free associative array (yup, reinvent the 
 wheel to introduce AA to the world of 'shared')
 2) In this small case it may seem best (though mind that often such 
 cases do grow up to the point when you still need to rethink design):
 Make your associative array __gshared and perform synchronization by 
 hand, i.e. create a static Mutex (from core.sync.mutex) variable and 
 initialize it in your CRegistry's static ctor, and then enclose all 
 access to associative array in synchronized(mutex) {} blocks.

 Maybe concurrent-programming-in-D guru may propose simpler solution, 
 but I don't see another.
FWIW, the classinfo of a class is an object, and as such can be used as sort of a global lock without having to use a static constructor: synchronized(this.classinfo) { .... } -Steve
Thanks. To my shame, I repeatedly keep forgetting about this.
Oct 07 2010
parent reply Bob Cowdery <bob bobcowdery.plus.com> writes:
 On 07/10/2010 21:32, Stanislav Blinov wrote:
 Steven Schveighoffer wrote:

 What I'd propose is either:
 1) Create your own lock-free associative array (yup, reinvent the
 wheel to introduce AA to the world of 'shared')
 2) In this small case it may seem best (though mind that often such
 cases do grow up to the point when you still need to rethink design):
 Make your associative array __gshared and perform synchronization by
 hand, i.e. create a static Mutex (from core.sync.mutex) variable and
 initialize it in your CRegistry's static ctor, and then enclose all
 access to associative array in synchronized(mutex) {} blocks.

 Maybe concurrent-programming-in-D guru may propose simpler solution,
 but I don't see another.
FWIW, the classinfo of a class is an object, and as such can be used as sort of a global lock without having to use a static constructor: synchronized(this.classinfo) { .... } -Steve
Thanks. To my shame, I repeatedly keep forgetting about this.
Thanks for the suggestions. I'm keen to avoid locks as everything so far is message parsing and the system is real-time. Having lots of threads that all talk to each other I needed a place to keep the Tid's which is accessible to everyone. There is no conflict because the main thread creates all others and registers the Tid's. Once the threads go the registry is read only. Just setting __gshared makes the app work. This may not be good practice I know and I will come back to it when I have more time. I'm not sure how to use synchronized(this.classinfo). Is this in combination with __gshared to synchronise access at the method level. Is it like a wrapper that goes inside the method? bob
Oct 08 2010
parent Stanislav Blinov <stanislav.blinov gmail.com> writes:
Bob Cowdery wrote:
  On 07/10/2010 21:32, Stanislav Blinov wrote:
 Steven Schveighoffer wrote:

 What I'd propose is either:
 1) Create your own lock-free associative array (yup, reinvent the
 wheel to introduce AA to the world of 'shared')
 2) In this small case it may seem best (though mind that often such
 cases do grow up to the point when you still need to rethink design):
 Make your associative array __gshared and perform synchronization by
 hand, i.e. create a static Mutex (from core.sync.mutex) variable and
 initialize it in your CRegistry's static ctor, and then enclose all
 access to associative array in synchronized(mutex) {} blocks.

 Maybe concurrent-programming-in-D guru may propose simpler solution,
 but I don't see another.
FWIW, the classinfo of a class is an object, and as such can be used as sort of a global lock without having to use a static constructor: synchronized(this.classinfo) { .... } -Steve
Thanks. To my shame, I repeatedly keep forgetting about this.
Thanks for the suggestions. I'm keen to avoid locks as everything so far is message parsing and the system is real-time. Having lots of threads that all talk to each other I needed a place to keep the Tid's which is accessible to everyone. There is no conflict because the main thread creates all others and registers the Tid's. Once the threads go the registry is read only. Just setting __gshared makes the app work. This may not be good practice I know and I will come back to it when I have more time. I'm not sure how to use synchronized(this.classinfo). Is this in combination with __gshared to synchronise access at the method level. Is it like a wrapper that goes inside the method? bob
Yeah, it's like this: static void register(E_PROC name, Tid tid) { synchronized(this.classinfo) { theRegistry[name] = tid; } } static Tid getTid(E_PROC name) { Tid* result; synchronized(this.classinfo) { result = name in TidRegistry; } //... } All Objects contain a 'monitor' which is a synchronization primitive. synchronized(some_object) { foo(); } is similar to { some_mutex.lock(); scope(exit) some_mutex.unlock(); // some code }
Oct 08 2010