Order of Static Construction
Steven Schveighoffer
schveiguy at gmail.com
Fri Jan 4 20:08:57 UTC 2019
On 1/4/19 11:48 AM, Neia Neutuladh wrote:
> On Fri, 04 Jan 2019 13:27:29 +0000, Dru wrote:
>> from the spec:
>> "Shared static constructors on all modules are run before any non-shared
>> static constructors."
>>
>> Is there a specific reason, or is it just for simplicity?
>>
>> There could be a situation where a shared ctor depends on a thread local
>> variable.
>> Preferably, the variable is only initialized in a non-shared ctor.
Unfortunately, that's not how it can work. Shared constructors run once
per program. So trivially, any thread run after main() has started will
be run after the shared ctors have run. Some thread-local constructors
depend on this, so you can't do it the other way around.
What you could do is initialize the logger in a function, then call that
function from either the shared or thread local constructor, depending
on whether it's already initialized or not (you can check without
locking, since it's a thread-local).
>
> This part of the spec isn't entirely correct. Consider:
>
> ---
> shared static this()
> {
> writeln("shared ctor start");
> new Thread({}).start;
> Thread.sleep(10.seconds);
> writeln("shared ctor done");
> }
> static this()
> {
> writeln("non-shared ctor");
> }
> ---
>
> This prints:
>
> shared ctor start
> non-shared ctor
> shared ctor done
Right. This supersedes the normal order, and can potentially cause issues.
> In order to fix this, the compiler would have to defer running threads
> until static constructors finish. But a static constructor that starts a
> thread could easily be waiting for it to finish and yield a result before
> continuing, leading to deadlocks.
Exactly right. There has been some abuse of what shared static
constructors are for in a lot of libraries. Until recently, vibe.d
encouraged putting the HTTP server setup into a static constructor,
including initializing the socket listeners. This kind of thing is prone
to errors, because you can't truly be certain of static construction of
everything in the first thread.
This would not be as bad of a problem if the shared constructors were
only allowed to access data initialized by shared constructors. But
there's no designation in D for that.
>
> In https://issues.dlang.org/show_bug.cgi?id=19492, I suggested a warning
> or error instead of trying to do the right thing.
>
Might be the right thing. Another possibility to still allow starting
threads from shared ctors is to wait for the shared ctors to finish, but
only yield an error if they don't finish in a certain amount of time
(like 4 seconds). That way, a thread can still be started if the shared
ctors don't depend on the execution of the thread progressing.
Should have some documentation to go along with this.
-Steve
More information about the Digitalmars-d
mailing list