View mode: basic / threaded / horizontal-split · Log in · Help
July 15, 2011
Static Destructors called early
Hi!

I'm having a pretty big mess just because my static destructors are
called before my non-static destructors. Now my question is; is this
related only to win32 applications where one uses runtime.terminate?

The problem is that I am using external libraries, and in one of these
cases you initialize the library and later on release it. I initialize
and release the library in static de-/constructors. The external library
I use is a sound library (FMOD). I have a sound class which uses library
functions which in turn needs the library to be *initialized* and not
*released*, when called. In the sound class, I release the sound file
in the destructor, but this fails because the static destructor (which
releases the library itself) has already been called, and therefore all
library function calls are invalid.

Are there any workarounds or solutions? And is it absolutely necessary
to use the runtime initialize and terminate functions, since it works
without any problems in a normal (non-win32) application.

From what I know, static de-/constructors are called when the main
function exits, but does it occur when the runtime, terminates when
using a win32 application?
July 16, 2011
Re: Static Destructors called early
On 7/16/2011 6:11 AM, Loopback wrote:
> Hi!
>
> I'm having a pretty big mess just because my static destructors are
> called before my non-static destructors. Now my question is; is this
> related only to win32 applications where one uses runtime.terminate?

You can never rely on when or if a destructor will be called unless you 
call them manually via delete (or, I suppose these days, clear()). For 
releasing system resources, you should handle it manually before the app 
exits.

>
> The problem is that I am using external libraries, and in one of these
> cases you initialize the library and later on release it. I initialize
> and release the library in static de-/constructors. The external library
> I use is a sound library (FMOD). I have a sound class which uses library
> functions which in turn needs the library to be *initialized* and not
> *released*, when called. In the sound class, I release the sound file
> in the destructor, but this fails because the static destructor (which
> releases the library itself) has already been called, and therefore all
> library function calls are invalid.
>
> Are there any workarounds or solutions? And is it absolutely necessary
> to use the runtime initialize and terminate functions, since it works
> without any problems in a normal (non-win32) application.

If you look in the source of your DMD2 installation directory and find 
the file src/druntime/src/rt/dmain2.d, you'll find the following function:

extern (C) int main(int argc, char** argv)

This is the normal application entry point when you use a D-style main. 
It handles runtime initialization/termination and calls your 
application's D-style main. However, if you use a WinMain function, that 
becomes the new entry point for the application. That's just the way 
Windows works. This means that the function in dmain2.d is never called 
and you have to handle the runtime's lifecycle yourself.

If you want to have a Windows application without a console popping up 
and without using WinMain, add this to your DMD command line:

-L/SUBSYSTEM:windows:5

If you need to support Windows 9x, replace the 5 with a 4.

>
>  From what I know, static de-/constructors are called when the main
> function exits, but does it occur when the runtime, terminates when
> using a win32 application?

It's the runtime that calls the static desconstructors during 
termination. Looking in source/druntime/src/core/runtime.d, you'll see 
that runtime.terminate calls the extern function rt_term. The rt_term 
function is implemented in dmain2.d, which I mentioned above. Looking 
there, you'll see the following:

_moduleTlsDtor();
thread_joinAll();
_d_isHalting = true;
_moduleDtor();
gc_term();

Notice the fourth line, _moduleDtor(). That's where all static module 
and class destructors are called. Then after that, the last line calls 
gc_term. This is where the class destructors are called. And that's why 
you are seeing the problem you have.

It doesn't matter if you use WinMain or main, this problem will always 
happen because of the order in which things are cleaned up. The solution 
is to never, ever, rely on order of destruction. All you can say 
generally is that static destructors will be run before the gc is 
terminated and that class destructors might be called at any time before 
(during the course of the program) or after (during temination).
Top | Discussion index | About this forum | D home