Thread overview | |||||||
---|---|---|---|---|---|---|---|
|
March 11, 2016 Iterating over thread local storage variables | ||||
---|---|---|---|---|
| ||||
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 Re: Iterating over thread local storage variables | ||||
---|---|---|---|---|
| ||||
Posted in reply to maik klein | 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 Re: Iterating over thread local storage variables | ||||
---|---|---|---|---|
| ||||
Posted in reply to Anonymouse | 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 Re: Iterating over thread local storage variables | ||||
---|---|---|---|---|
| ||||
Posted in reply to sigod | 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 Re: Iterating over thread local storage variables | ||||
---|---|---|---|---|
| ||||
Posted in reply to Anonymouse | 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.
|
Copyright © 1999-2021 by the D Language Foundation