KeldorKatarn

I am trying to get the PhoenixSingleton pattern example found in "Modern C++ Design" to run. I am using the Singleton in a DLL.
I don't deliver any references of the Singleton to outside-DLL callers so that's not my problem. The singleton works perfectly, the only problem is.. after reviving the singleton, it doesn't get destroyed, meaning the destructor is not called.
I checked that by using the DLL in a simple test application and sending messages to std::cout in every member function.
Every single function is called in the correct order as soon as the DLL is unloaded, the Singleton gets destroyed for the first time, it gets revived.. but the destructor doesn't get called a second time. Somehow I suspect atexit() doesn't work here.

I am using Visual Studio 2005 and I already tried using _onexit() but that thing doesn't seem to accept member function pointers at least I always get conversion errors there.

Any ideas or insights on how to get this to work
The object that I put into the singleton is just a simple logging class
that I use in my application to write simple statements to a textfile and that holds only a fstream object, so when the application is terminated there shouldn't be any ressource leaks even if the destructor isn't called but being the perfectionist I am I'd like this to work as it is supposed to.

Thanks in advance


Re: Visual C++ Language Problems with atexit() in a DLL

Shakje

Could you post some code please.




Re: Visual C++ Language Problems with atexit() in a DLL

KeldorKatarn

Code Snippet

//----------------------------PhoenixSingleton.h-----------------------------

#include <cstdlib>

template <class T>
class PhoenixSingleton : public T
{
public:

static PhoenixSingleton& GetInstance();

private:

// Constructors, destructor and assignment operator
// Declared private to prevent usage
PhoenixSingleton();
PhoenixSingleton(const PhoenixSingleton& source);
PhoenixSingleton& operator=(const PhoenixSingleton& source);
virtual ~PhoenixSingleton();

// Private methods
static void CreateInstance();
static void DestroyInstance();
static void ReviveInstance();

// Attributes
static PhoenixSingleton* pInstance_;
static bool isInstanceDestroyed_;

}; // class PhoenixSingleton

template <class T>
PhoenixSingleton<T>& PhoenixSingleton<T>::GetInstance()
{
if (NULL == pInstance_)
{
// Check if reference is dead
if (isInstanceDestroyed_)
{
ReviveInstance();
}
else
{
CreateInstance();
}
}

return *pInstance_;

} // GetInstance()

template <class T>
PhoenixSingleton<T>::PhoenixSingleton()
{
} // PhoenixSingleton()


template <class T>
PhoenixSingleton<T>::~PhoenixSingleton()
{
pInstance_ = NULL;
isInstanceDestroyed_ = true;

} // ~PhoenixSingleton()


template <class T>
void PhoenixSingleton<T>::CreateInstance()
{
static PhoenixSingleton<T> objectInstance;
pInstance_ = &objectInstance;

} // CreateInstance()


template <class T>
void PhoenixSingleton<T>::DestroyInstance()
{
pInstance_->~PhoenixSingleton();

} // DestroyInstance()


template <class T>
void PhoenixSingleton<T>::ReviveInstance()
{
CreateInstance();

// Put new instance in the 'hull' of the old one
new(pInstance_) PhoenixSingleton<T>;

// Mark for destruction
atexit(DestroyInstance);

isInstanceDestroyed_ = false;

} // ReviveInstance()


template <class T>
PhoenixSingleton<T>* PhoenixSingleton<T>::pInstance_ = NULL;


template <class T>
bool PhoenixSingleton<T>::isInstanceDestroyed_ = false;







Re: Visual C++ Language Problems with atexit() in a DLL

einaros

How are you unloading the dll

The atexit callbacks will be executed on crt shutdown, and that should happen for each call to e.g. FreeLibrary. If your application calls LoadLibrary, FreeLibrary, then LoadLibrary and FreeLibrary a second time, I don't see how the atexit callback shouldn't be executed.

If the problem persists, it would be great if you could shed some light on the lifecycle of your application.





Re: Visual C++ Language Problems with atexit() in a DLL

KeldorKatarn

I am not loading or unloading it manually at all. I just set it as a dependency in the project's properties.

in comp.os.ms-windows.programmer.win32 I got an interesting opinion so far:

Jan Ringo wrote:
> The standard is kinda weak when talking about atexit. I don't use VS2005
> but you generaly can't be sure if you can or can not add more pointers
> during program termination.




Re: Visual C++ Language Problems with atexit() in a DLL

Holger Grund

In that case your DLL should be get a process detach notification on process shutdown which will trigger CRT cleanup including invoking atexit functions.

You certainly shouldn't call atexit during cleanup, but I don't see where you do it. I only see one explicit atexit call and one local static with a nontrivial destructor (basically, the compiler generates a call to atexit with the dtor, which is executed on first entry to the function). That kind of race condition should only occur if you call GetInstance for the first time from within CRT cleanup.

It is also worth mentioning that cleanup under the loader lock (which includes destruction of local static variables, global variables and static data members) has some problems. That a look at the DllMain documentation - specifically the DLL_PROCESS_DETACH.

-hg





Re: Visual C++ Language Problems with atexit() in a DLL

KeldorKatarn

Holger Grund wrote:

You certainly shouldn't call atexit during cleanup, but I don't see where you do it. I only see one explicit atexit call and one local static with a nontrivial destructor (basically, the compiler generates a call to atexit with the dtor, which is executed on first entry to the function). That kind of race condition should only occur if you call GetInstance for the first time from within CRT cleanup.



That's exactly what happens.

The singleton is wrapped around a logging class I implemented.

And I call getInstance() in the destructor of another Singleton which is also static of course so it's destructor is called within CRT cleanup.
I want to be able to log errors that happen within that destructor if any happen.

This works without problems if all this is done within an application. That's the whole idea behind the PhoenixSingleton pattern anyway. The only time this doesn't happen is when I have the singleton inside a DLL and use that DLL in an application. Everything works find, at stack cleanup the destructor of my normal Singleton calls getInstance() of my PhoenixSingleton, it revives itself, but after that the destructor isn't called although it should have been registered by atexit().