From: Jeremy Pack (rostovpack_at_[hidden])
Date: 2008-07-07 22:42:42


Robert,

> I'm developing a plugin system and I will be loading several DLLs.
> Basically, as far as I know, this means having one factory_map per DLL
> (on Windows).

This depends on how you want to use the factory_maps. Do you want to close
the shared libraries that you aren't using? If not, just use the same
factory_map for every shared library. Unless you have a LOT of separate
shared libraries, this is usually a good solution (if you have a lot, you
may not want the unused libraries taking up RAM).

If you do want to close unused shared libraries, it's a bit trickier. I had
some code that did this, but have let it languish because it didn't cover a
number of special cases. Here is more or less how it worked:

   - Create a counted_factory_map instead of a factory_map. Internally, a
   counted_factory_map contains a separate map and shared_library object for
   each shared library.
   - Whenever you ask it to add a constructor for a class T, it instead adds
   a constructor for a class counted<T> (which is a derived class of T), which
   increments and decrements a counter whenever it is created or destroyed.
   - There is a function in the shared library that can be called to see how
   many objects are currently live from the given shared library.
   - You can call a function on the counted_factory_map to do garbage
   collection - ie, close shared libraries with no live objects.

The reasons this code is not currently used in Extension:

   - It requires a duplicate of almost every class in Extension - a counted
   version and a non-counted version.
   - The counted versions have very high coupling - whereas the uncounted
   versions of shared_library and factory_map are very loosely coupled. It also
   makes it impossible to use parameter_map in its current form.
   - It requires, in the common case, the use of mutexes to protect the
   counters. This requires linking in the Thread library.
   - It only works if all you are doing in a shared library is constructing
   objects using counted_factory. If you take a reference to anything else in a
   shared library, you risk having a dangling reference when all of the
   counted<T> objects are destroyed. Note that this can be alleviated by using
   a separate shared_library instance if you want to do anything besides
   populate a counted_factory_map, since a shared library is only closed when
   all shared_library instances referencing it are destroyed (it is also
   possible to force a shared library to remain open until program termination
   - by passing false as the second parameter to the shared_library
   constructor).

There were a few other special cases that broke it as well - but I can't
remember what they were right now.

I can update that code if people are interested. I certainly wouldn't mind
suggestions about how to avoid some of the problems that I listed, or a
different way of handling this sort of "garbage collection" of unused shared
libraries.

Thanks!

Jeremy Pack