Thread overview | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
January 04, 2019 Order of Static Construction | ||||
---|---|---|---|---|
| ||||
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. |
January 04, 2019 Re: Order of Static Construction | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dru | On Friday, 4 January 2019 at 13:27:29 UTC, 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.
The shared static constructor would only be able to access one of the thread-local variables (probably from the main thread). That isn't very useful. It'd be more useful to have thread local static constructors access variables that were constructed in the shared static constructor. The thread constructor is called any time a new thread is created, and you can create a new thread any time at runtime. It'd be impossible to guarantee the shared static constructor is called after all the thread local constructors unless you put a bunch of restrictions on threads.
|
January 04, 2019 Re: Order of Static Construction | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dru | 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. 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 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. In https://issues.dlang.org/show_bug.cgi?id=19492, I suggested a warning or error instead of trying to do the right thing. |
January 04, 2019 Re: Order of Static Construction | ||||
---|---|---|---|---|
| ||||
Posted in reply to Rubn | @Rubn yes from the main thread I'll give a specific example lets say every thread has its own log so log should be a thread local object and lets say we want to log from a shared static ctor log module ----------- (define Log class ...) Log log; static this() { log = new Log; } other module ----------- import log_module; (define other class ...) shared Other other; shared static this() { log.write("creating other"); //seg fault log is null! other = new Other; } @Neia Neutuladh you're right the statement doesn't consider starting threads. if we strictly follow the spec then yes it should error, but I think maybe we should change the spec and mix between shared/non-shared if there isn't a good reason not to |
January 04, 2019 Re: Order of Static Construction | ||||
---|---|---|---|---|
| ||||
Posted in reply to Neia Neutuladh | 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 |
January 05, 2019 Re: Order of Static Construction | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | Construction order is resolved by module dependencies (import statements) In the main thread ---------------------- Currently, shared and thread-local construction are separated. Instead we could "construct a module", i.e run both shared and thread-local construction for that module, then continue to construct the next module. |
January 07, 2019 Re: Order of Static Construction | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dru | On 1/5/19 10:22 AM, Dru wrote:
> Construction order is resolved by module dependencies (import statements)
>
> In the main thread
> ----------------------
> Currently, shared and thread-local construction are separated.
>
> Instead we could "construct a module", i.e run both shared and thread-local construction for that module, then continue to construct the next module.
This is a really good idea, actually. I hadn't thought of that approach at all. I think it can be done in druntime as well, without depending on compiler changes.
I will post an enhancement request to track it. Thanks!
-Steve
|
January 07, 2019 Re: Order of Static Construction | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On 1/7/19 5:02 PM, Steven Schveighoffer wrote:
> On 1/5/19 10:22 AM, Dru wrote:
>> Construction order is resolved by module dependencies (import statements)
>>
>> In the main thread
>> ----------------------
>> Currently, shared and thread-local construction are separated.
>>
>> Instead we could "construct a module", i.e run both shared and thread-local construction for that module, then continue to construct the next module.
>
> This is a really good idea, actually. I hadn't thought of that approach at all. I think it can be done in druntime as well, without depending on compiler changes.
>
> I will post an enhancement request to track it. Thanks!
Note that this still doesn't solve the current problem of a thread running static ctors before the main thread's shared static ctors are done. We should deal with that as well.
-Steve
|
January 07, 2019 Re: Order of Static Construction | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On 1/7/19 5:02 PM, Steven Schveighoffer wrote: > I will post an enhancement request to track it. Thanks! https://issues.dlang.org/show_bug.cgi?id=19556 -Steve |
Copyright © 1999-2021 by the D Language Foundation