Boost logo

Boost :

From: Vladimir Prus (ghost_at_[hidden])
Date: 2005-08-19 01:30:04


Robert Ramey wrote:

> Vladimir Prus wrote:
>> I think you're going contrary to the basic threading assumption in
>> the C++. If I explicitly use the same object from two different
>> threads, I must use locking myself.
>
> This is what I disagree with. I don't any problem with multiple threads
> accessing the same data structures as long as the accesses are read-only
> and the structures are not being modified.
>
>>If, for all appearence, I don't
>> use the same object in two threads, but there's some *internal*
>> shared data structure, it should be protected *internally*. In this
>> case, there's some internal serialization table that I know nothing
>> about, so it should be protected by serialization library.
>
> Repeat, I don't think this is necessary.

Dave has already commented on this point: if the structures are modified by
some thread, you need locking.

>>Besides, I don't understand how you
>> can "inhibit loading of DLLS". Say, one thread has created an archive
>> and does something with it. Some other thread tries to open DLL. What
>> should happen? Should that other thread get "sorry, some archives are
>> open" error? And what
>> will it do?
>
> A couple of possibilities. It could somehow check to see that no archives
> are open. (The serialization library might have to add support for this).
> It could throw an exception if an attempt is made to change a global
> structure when when an archive is open.
>
>>Wait until the other thread is done with archive? And what if
>> the other thread uses archive to talk over network and will never
>> close the achrive? And even if it will close archive, how will the
>> other thread wait for that? There's no public method that tells that
>> any archive is open.
>
> Correct, but this could be remedied without dragging threads in to it.

Okay, but then assume the following scenario:

1. A program creates an archive to read from network connection. Network
connection is never to be closed.

2. A command arrives via connection that requires loading a plugin.

3. The plugin has BOOST_CLASS_EXPORT, so attempt to load it crashes. We have
   two possibilities:

3a. Since the exception happens when you modified serialization tables, and
that happens in static initializer, you cannot catch the exception anywhere
in the plugin code. Since the plugin (on Unix), is opened with C function
dlopen, it's not clear if the exception will propagated across that C
function. So, the whole application might crash.

3b. Assume we checked if archives are opened before calling dlopen.
Actually, we cannot, because we don't know, generally speaking, if the
plugin uses BOOST_CLASS_EXPORT or not. But assume we somehow know this and
figured that we can't load the plugin. Now:
    
      - we can't close the network connection, because it waits for
        further commands
      - we can't load plugin because some archive is opened, so we can
        do the previous command we've received

Neither alternative looks particularly attractive to me.

> There's another aspect here. The code for serialization presumes that the
> global tables are static during the lifetime of the archive. For example,
> as a particular item is serialized, its class identifier is saved in an
> archive specific table. Thus the save code used the object identifier to
> invoke the save method for the specific class. Same goes for the load
> side. Now, if the global table changes while an archive is open, all bets
> are off
> because the save/load code may not be around anymore. So.
>
> a) global tables can't be changed while an archive is open an still expect
> the system to function.

This is over-generalisation. Clearly, new BOOST_CLASS_EXPORT statements
won't break anything.

> b) thus DLLS should be loaded/unloaded only when there are no archives
> open.

It's only disallowed to save/load objects that come from DLL and registered
in global id table for which the corresponding DLL is unloaded. What this
means is that ids should be removed from global table on DLL unload -- I
think this can be done by implementing a destructor in the same helper
classes that registers id in its constructor.

> c) respecting this rule is the responsability of the calling
> program.

As I've shown above, it's not always possible to respect this rule.

> While we're at it, I would also like to consider enforcing a rule that
> there can be at most one instance of serialization code for a specific
> type existing at one time.

What do you mean? If there are two DLL defining the same function but with
different bodies, that's ODR violation. If they define the same function
with the same body, that's no problem.

- Volodya


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk