Potential Static Deinitialisation Problem?

Started by
3 comments, last by Trapper Zoid 16 years, 11 months ago
Hi everyone, I am currently working on a 2D game library that uses a signal/slot system as the backbone to communicate between different modules. At present I'm still in the starting phases; I've got a signal/slot class implemented which uses Boost Pool as a memory pool to hold the data structures that store the links between signals and slots. I am now trying to sketch out how to code the kernel (main game loop) and how to implement the interfaces between modules. Since I am using signals as an interface method the simplest method would be to have key signals declared as static global objects to allow other modules to connect up to them. However there's a potential snag here that I'm not sure how to get around. The problem is that the signals need to use a globally static memory pool (implemented as a Boost Pool) to allocate a series of data structures to model the connection between slots. Boost Pool's documentation states that this should be safe from the static initialisation problem, where it is uncertain in what order static objects will be initialised when the program starts. However the signal classes also need to delete connections on destruction, and so they have to call the memory pool in their destructor. Thus I don't know if there's a problem at the end of the program; the pool needs to be destroyed last otherwise the signals may call a non-existent entity. Is this correct, and if so what is a good way around this problem? Edit:BTW, I'm programming in C++ (hence the use of Boost), in case that isn't clear. I keep forgetting to mention that explicitly. [Edited by - Trapper Zoid on May 9, 2007 6:44:51 PM]
Advertisement
In case I wasn't clear with my problem description, I'll post some code to help explain.

My signal system uses a memory pool from Boost to store data structures called "connections" that contain important info such as function pointers and linked list connection pointers. Here's the typedef that declares my memory pool type:
typedef boost::singleton_pool<connection, sizeof(connection)> ConnectionMemoryPool;
I've used this to declare a series of signal classes that I want to use to connect modules between each other in a decoupled way. Modules can contain a set of signals that other modules can connect to.

For some modules it makes sense to declare the signals as static in the global space in one way or another. The simplest way would be something like:
static Signal0 mySampleSignal;
...with a corresponding extern in the header file. Or these could be wrapped up in a global class or a singleton or some other way of ensuring global access to any module that wants to sign up to that signal.

The problem is with deinitialisation; when the program ends I don't know what order all those static declarations will be deleted from. Unfortunately the Signal0 has to disconnect all the connections it has, which involves calling a function to the boost memory pool. This is fine if the Boost pool deallocates all its memory after all the static signals, but I don't know if that can be guaranteed. It seems to be working with my current tests but that doesn't prove it to be the case in general. If the Boost pool gets deinitialised before the signal does, then I am afraid that Bad StuffTM will happen.

The questions I'm unsure about are:
  • is this actually a problem?
  • and if so, what is a good way to fix or get around it?


Thanks for any advice!
Quote:Original post by Trapper Zoid
The questions I'm unsure about are:
  • is this actually a problem?
  • and if so, what is a good way to fix or get around it?


- If you can guarantee that the memory pool is being created before any Signal0 objects, then it will also be deallocated after any Signal0 objects, and in this case you don't have a problem - static objects "are destroyed in the reverse order of the completion of their constructor or of the completion of their dynamic initialization" [C++ standard 3.6.3].
- If you can allocate a Signal0 object before the memory pool, then you're opening a potential can of worms, as these objects will be deallocated after the memory pool, leading to bad juju.

Some possible solutions off the top of my head:
- Ensure that the memory pool will always be created before any Signal0 objects (e.g. the construction of a Signal0 depends on a memory pool object being available).
- Allow the memory pool to remove any dependency on itself from the Signal0 objects (e.g. in the memory pool destructor, go through each associated Signal0 object and reset any connections to the memory pool).
- Replace static Signal0 lifetimes with something you can explicitly control (e.g. pointers to dynamically allocated Signal0 instances).

I hope this helps... if not, then it's a free bump at least! [smile]
Quote:Original post by Trapper Zoid
The problem is with deinitialisation; when the program ends I don't know what order all those static declarations will be deleted from.


Google for the "nifty counter" technique. It's nifty. It's a counter. It's how the C++ standard library handles initialization and deinitialization of cin/cout/cerr/clog.

Stephen M. Webb
Professional Free Software Developer

Thanks for the replies. I've had a deeper look into the issue, searching the web for more understanding of how the compiler and linker works and reading the singleton header used by Boost's pool system.

In my case I now think deinitialisation is not going to be a problem as the contructors of all my signals use the boost pool too. If my understanding is correct, this means the Boost pool must be initialised before the contructor is run (due to the singleton code) and thus must be deinitialised after the destructor is called. Hence I can use global static signals if I want to without worring about static (de)initialisation problems.

This topic is closed to new replies.

Advertisement