Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

order of destruction, singletons & std::ostream

4 views
Skip to first unread message

ThosRTanner

unread,
Aug 8, 2007, 11:54:45 AM8/8/07
to
We have a class in our system which is a singleton and it has 2
std::auto_ptr<std::ostream> members.

You get hold of the instance by calling the getInstance() method which
is inlined and does
inline Fred& Fred::getInstance() { static Fred fred; return fred; }

And the program is multithreaded. Running on solaris, in case that is
relevant.

The issue is that sometimes on exit the program hangs, apparently
trying to acquire a mutex in the destructor of one of the ostream
objects. This destructor is called as the result of calling exit(0)
from the main program. And one of the other threads is still running,
and it is also locked on a mutex, though as far as I can see it is a
different mutex.

I realise that threading isn't covered by the standard, but is it safe
to get hold of pointers to ostream objects like that and then let them
be cleaned up during exit processing (especially as, as far as I can
see, the object won't have been constructed till well after main())
has been entered.

Thanks


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Denise Kleingeist

unread,
Aug 8, 2007, 11:20:28 PM8/8/07
to
Hello!

On Aug 8, 5:54 pm, ThosRTanner <ttann...@bloomberg.net> wrote:
> The issue is that sometimes on exit the program hangs, apparently
> trying to acquire a mutex in the destructor of one of the ostream
> objects. This destructor is called as the result of calling exit(0)
> from the main program. And one of the other threads is still running,
> and it is also locked on a mutex, though as far as I can see it is a
> different mutex.

The destruction order upon exit is a mess and even harder to control
than the construction order: the latter can be controlled by using
static
variables within functions but this doesn't really work well with
destruction. My understanding is that the objects are destroyed in the
reverse order of their construction but this isn't necessary what you
really want.

For global streams, my experience is that it is best to not destroy
them
at all. Instead, when destroying the containing object you could just
flush the stream and set it up to automatically flush any further
output
sent to it (using std::unitbuf). This way, any really necessary "clean-
up",
i.e. flushing the buffer is done without running the risk of permature
destruction of the object. In addition, the destruction shouldn't run
into
any issues with objects trying to lock a possibly already destroyed
mutex.

Good luck, Denise.

Roman.Pe...@gmail.com

unread,
Aug 9, 2007, 7:07:03 AM8/9/07
to
> We have a class in our system which is a singleton and it has 2
> std::auto_ptr<std::ostream> members.
>
> You get hold of the instance by calling the getInstance() method which
> is inlined and does
> inline Fred& Fred::getInstance() { static Fred fred; return fred; }
>
> And the program is multithreaded. Running on solaris, in case that is
> relevant.
>
> The issue is that sometimes on exit the program hangs, apparently
> trying to acquire a mutex in the destructor of one of the ostream
> objects. This destructor is called as the result of calling exit(0)
> from the main program. And one of the other threads is still running,
> and it is also locked on a mutex, though as far as I can see it is a
> different mutex.
>
> I realise that threading isn't covered by the standard, but is it safe
> to get hold of pointers to ostream objects like that and then let them
> be cleaned up during exit processing (especially as, as far as I can
> see, the object won't have been constructed till well after main())
> has been entered.

I didn't understand the issue with std::auto_ptr<std::ostream>
members,
but probably you have problems because of thread unsafe singleton
implementation.

inline Fred& Fred::getInstance() { static Fred fred; return fred; }

Compiler generates code like this:

static bool fred_initialized = false;
static char fred_store[Alignment_of_Fred];

void destroy_fred()
{ static_cast<Fred*>((void*)fred_store)->~Fred(); }

inline Fred& Fred::getInstance()
{
if (!fred_initialized)
{
new (fred_store) Fred();
atexit(destroy_fred);
fred_initialized = true;
}
return *static_cast<Fred*>((void*)fred_store);
}

This code is not thread safe. It can lead to double
destructor call for Fred. It can lead to use of
uninitialized Fred object as well.

To make it thread safe one uses call_once function.

static boost::once_flag flag = BOOST_ONCE_INIT;

struct Fred
{
Fred & getInstance()
{
boost::call_once(&Fred::init, flag);
return *self;
}
private:
static init() { static Fred fred; self = &fred; }
static volatile Fred * self;
};

Roman Perepelitsa.

Maxim Yegorushkin

unread,
Aug 10, 2007, 2:26:20 PM8/10/07
to
On 8 Aug, 16:54, ThosRTanner <ttann...@bloomberg.net> wrote:
> We have a class in our system which is a singleton and it has 2
> std::auto_ptr<std::ostream> members.
>
> You get hold of the instance by calling the getInstance() method which
> is inlined and does
> inline Fred& Fred::getInstance() { static Fred fred; return fred; }
>
> And the program is multithreaded. Running on solaris, in case that is
> relevant.
>
> The issue is that sometimes on exit the program hangs, apparently
> trying to acquire a mutex in the destructor of one of the ostream
> objects. This destructor is called as the result of calling exit(0)
> from the main program. And one of the other threads is still running,
> and it is also locked on a mutex, though as far as I can see it is a
> different mutex.
>
> I realise that threading isn't covered by the standard, but is it safe
> to get hold of pointers to ostream objects like that and then let them
> be cleaned up during exit processing (especially as, as far as I can
> see, the object won't have been constructed till well after main())
> has been entered.

The problem seems to stem from the C/C++ and POSIX standards not
mentioning whether the other threads have been terminated when
atexit() handlers are being executed.

This particular case sounds like a deadlock: your destructor thread
gets blocked on a mutex. One possible fix would be to let the other
threads terminate gracefully (releasing mutexes and other resources)
before calling exit(), thus eliminating the possibility of the
deadlock.

0 new messages