Thread overview
Iterating over thread local storage variables
Mar 11, 2016
maik klein
Mar 11, 2016
Anonymouse
Mar 11, 2016
sigod
Mar 11, 2016
Anonymouse
Mar 11, 2016
sigod
March 11, 2016
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?

March 11, 2016
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.
March 11, 2016
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
March 11, 2016
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.
March 11, 2016
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.