Thread overview | |||||||
---|---|---|---|---|---|---|---|
|
March 03, 2013 module initialization order issue | ||||
---|---|---|---|---|
| ||||
When modules are initialized, druntime will first run the module initializers before running the module tls initializers ignoring the dependencies between the modules. This will lead to a access of a unitialized module if the module ctor of one module uses tls data of another module. Example: module a: class TLSStuff { public int i; } TLSStuff g_tlsStuff; static this() { g_tlsStuff = new TLSStuff(); } module b: import a; shared static this() { g_tlsStuff.i++; //null pointer access } Is this a bug, or is this intended beahvior? I always believed that with all the dependency detenction that is done such situation should not happen. Kind Regards Benjamin Thaut |
March 03, 2013 Re: module initialization order issue | ||||
---|---|---|---|---|
| ||||
Posted in reply to Benjamin Thaut | On Sunday, 3 March 2013 at 12:01:10 UTC, Benjamin Thaut wrote:
> Is this a bug, or is this intended beahvior? I always believed that with all the dependency detenction that is done such situation should not happen.
It's intended behaviour.
Remember that shared static this() is only run once for the whole program, whereas static this() is run per thread. Using per-thread data inside something that's run per-program doesn't make a whole lot of sense.
|
March 03, 2013 Re: module initialization order issue | ||||
---|---|---|---|---|
| ||||
Posted in reply to Peter Alexander | Am 03.03.2013 16:29, schrieb Peter Alexander:
> On Sunday, 3 March 2013 at 12:01:10 UTC, Benjamin Thaut wrote:
>> Is this a bug, or is this intended beahvior? I always believed that
>> with all the dependency detenction that is done such situation should
>> not happen.
>
> It's intended behaviour.
>
> Remember that shared static this() is only run once for the whole
> program, whereas static this() is run per thread. Using per-thread data
> inside something that's run per-program doesn't make a whole lot of sense.
Well this is of course a reduced version of a real issue I'm having. I have thread local stack allocators. Each thread has its own stack allocator and certain parts of my code use these. What happened now is, that I inserted a call into a shared static module constructor which calls a function which in turn uses a thread local stack allocator. The problem is, that the thread local stack allocator module is not fully initialized at that point.
But I think I can work around it by adding a shared static constructor and initialize the thread local stack alloactor for the main thread there.
Kind Regards
Benjamin Thaut
|
March 03, 2013 Re: module initialization order issue | ||||
---|---|---|---|---|
| ||||
Posted in reply to Benjamin Thaut | On Sunday, 3 March 2013 at 16:07:58 UTC, Benjamin Thaut wrote:
> Am 03.03.2013 16:29, schrieb Peter Alexander:
>> On Sunday, 3 March 2013 at 12:01:10 UTC, Benjamin Thaut wrote:
>>> Is this a bug, or is this intended beahvior? I always believed that
>>> with all the dependency detenction that is done such situation should
>>> not happen.
>>
>> It's intended behaviour.
>>
>> Remember that shared static this() is only run once for the whole
>> program, whereas static this() is run per thread. Using per-thread data
>> inside something that's run per-program doesn't make a whole lot of sense.
>
> Well this is of course a reduced version of a real issue I'm having. I have thread local stack allocators. Each thread has its own stack allocator and certain parts of my code use these. What happened now is, that I inserted a call into a shared static module constructor which calls a function which in turn uses a thread local stack allocator. The problem is, that the thread local stack allocator module is not fully initialized at that point.
>
> But I think I can work around it by adding a shared static constructor and initialize the thread local stack alloactor for the main thread there.
It's a tricky situation. There are bad situations no matter which order things happen.
At least the order is defined. Having this kind of thing break in non-deterministic ways would be a lot less fun.
|
March 04, 2013 Re: module initialization order issue | ||||
---|---|---|---|---|
| ||||
Posted in reply to Benjamin Thaut | On Sun, 03 Mar 2013 07:01:11 -0500, Benjamin Thaut <code@benjamin-thaut.de> wrote:
> When modules are initialized, druntime will first run the module initializers before running the module tls initializers ignoring the dependencies between the modules. This will lead to a access of a unitialized module if the module ctor of one module uses tls data of another module. Example:
>
> module a:
>
> class TLSStuff
> {
> public int i;
> }
>
> TLSStuff g_tlsStuff;
>
> static this()
> {
> g_tlsStuff = new TLSStuff();
> }
>
> module b:
> import a;
>
> shared static this()
> {
> g_tlsStuff.i++; //null pointer access
> }
>
> Is this a bug, or is this intended beahvior? I always believed that with all the dependency detenction that is done such situation should not happen.
As has been discussed, this is intended behavior.
But I will go a bit further. It is reasonable to assume that each thread being allocated will be assured that the shared data has already been initialized. This makes logical sense as the shared data is initialized once, thread data is initialized whenever you start a new one.
So if we had the shared data depending on the first thread local data being initialized, you couldn't have ANY thread local data depending on the shared data being initialized. I don't think this is the right decision.
But how can we solve this problem? One possibility, while a bit awkward, is to identify when you are initializing the first thread. Then use that knowledge to your advantage:
__gshared bool inFirstThread = true;
static this()
{
if(inFirstThread) // shared constructor already has initialized tls stuff for us
inFirstThread = false;
else
g_tlsStuff = new TLSStuff();
}
shared static this()
{
// initialize main thread's tls stuff
g_tlsStuff = new TLSStuff();
g_tlsStuff.i++;
}
If you needed this idiom elsewhere, you could set the inFirstThread to false as the first statement in main. Druntime could conceivably do something like this for you, if you are so inclined, file an enhancement.
-Steve
|
Copyright © 1999-2021 by the D Language Foundation