www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Iterating over thread local storage variables

reply maik klein <maikklein googlemail.com> writes:
I want to create a logger in a multithreaded system. I wanted to 
expose a global variable like

logger.log("something");

I also wanted to reuse D's thread local global variables because 
that would make it easy to log in a multithreaded system.

This is really easy to do, but the problem is that at one point I 
need to collect all `loggers` and merge them.

So I thought about writing something like this:

import std.stdio;
class Singleton(T)
{
     import std.container: Array;
     private this() {}

     // Cache instantiation flag in thread-local bool
     // Thread local
     private static bool instantiated_;

     // Thread global
     private __gshared Singleton!T instance_;

     static Singleton!T get()
     {
         if (!instantiated_)
             {
             synchronized(Singleton!T.classinfo){
                 if (!instance_){
                     instance_ = new Singleton!T();
                 }
                 instantiated_ = true;
                 instance_.tls.insertBack(&instance_.value);
             }
         }

         return instance_;
     }
     __gshared Array!(T*) tls;
     static T value;
}
unittest{
     import std.concurrency;
     import core.thread;
     auto s = Singleton!int.get();
     foreach(index; 0..10){
         spawn((int a){
             auto s = Singleton!int.get();
             s.value = a;
         }, index);
     }
     Thread.sleep( dur!("seconds")( 1 ) );
     writeln("--");
     foreach(p; s.tls){
         writeln(*p);
     }
}

Basically every time `instantiated_` is false, I know that I am 
on a new thread and then I push the reference of `value` into a 
global array.

But how do I access `tls` in a thread safe manner?

Is there another way of doing this?
Mar 11 2016
parent reply Anonymouse <asdf asdf.com> writes:
On Friday, 11 March 2016 at 15:21:38 UTC, maik klein wrote:
     static Singleton!T get()
     {
         if (!instantiated_)
             {
             synchronized(Singleton!T.classinfo){
                 if (!instance_){
                     instance_ = new Singleton!T();
                 }
                 instantiated_ = true;
                 instance_.tls.insertBack(&instance_.value);
As a drive-by comment, mind that there is a race there. _instantiated may have been set after the if statement but before the synchronized block. You have to test it again inside.
Mar 11 2016
parent reply sigod <sigod.mail gmail.com> writes:
On Friday, 11 March 2016 at 17:03:38 UTC, Anonymouse wrote:
 On Friday, 11 March 2016 at 15:21:38 UTC, maik klein wrote:
     static Singleton!T get()
     {
         if (!instantiated_)
             {
             synchronized(Singleton!T.classinfo){
                 if (!instance_){
                     instance_ = new Singleton!T();
                 }
                 instantiated_ = true;
                 instance_.tls.insertBack(&instance_.value);
As a drive-by comment, mind that there is a race there. _instantiated may have been set after the if statement but before the synchronized block. You have to test it again inside.
That's why inside of `synchronized` block you can see `if (!instance_)`. Watch this for details: https://www.youtube.com/watch?v=yMNMV9JlkcQ&t=27m54s
Mar 11 2016
parent reply Anonymouse <asdf asdf.com> writes:
On Friday, 11 March 2016 at 17:33:43 UTC, sigod wrote:
 On Friday, 11 March 2016 at 17:03:38 UTC, Anonymouse wrote:
 On Friday, 11 March 2016 at 15:21:38 UTC, maik klein wrote:
     static Singleton!T get()
     {
         if (!instantiated_)
             {
             synchronized(Singleton!T.classinfo){
                 if (!instance_){
                     instance_ = new Singleton!T();
                 }
                 instantiated_ = true;
                 instance_.tls.insertBack(&instance_.value);
As a drive-by comment, mind that there is a race there. _instantiated may have been set after the if statement but before the synchronized block. You have to test it again inside.
That's why inside of `synchronized` block you can see `if (!instance_)`.
It does, yes, but it also calls instance_.tls.insertBack unconditionally. To illustrate: http://dpaste.dzfl.pl/8f3e78f3265a7 Apologies for derailing.
Mar 11 2016
parent sigod <sigod.mail gmail.com> writes:
On Friday, 11 March 2016 at 18:45:13 UTC, Anonymouse wrote:
 On Friday, 11 March 2016 at 17:33:43 UTC, sigod wrote:
 On Friday, 11 March 2016 at 17:03:38 UTC, Anonymouse wrote:
 On Friday, 11 March 2016 at 15:21:38 UTC, maik klein wrote:
                 [...]
As a drive-by comment, mind that there is a race there. _instantiated may have been set after the if statement but before the synchronized block. You have to test it again inside.
That's why inside of `synchronized` block you can see `if (!instance_)`.
It does, yes, but it also calls instance_.tls.insertBack unconditionally. To illustrate: http://dpaste.dzfl.pl/8f3e78f3265a7 Apologies for derailing.
Indeed. You're right. I didn't even look at `instance_.tls...` line. I guess `insertBack` just need to be moved inside of `if (!instance_)` scope.
Mar 11 2016