By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,134 Members | 1,796 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,134 IT Pros & Developers. It's quick & easy.

Destructor semantics

P: n/a

Is my understanding right here?

An object becomes totally inaccessible only after its dtor runs through
completely, right?

I have a situation where I need to hang around in the dtor of an
automatic object for a while -- this is to let various threads that
have access to my automatic object shutdown gracefully.

I do not want main() to return when myclass::runInfinitely() happens to
throw an exception without giving a chance for worker threads to die.

Currently I do it like this:

int main()
{
try
{
myclass myclassObj;
spawnthreads(&myclassObj);
myclass.runInfinitely();
}
catch(...)
{
}
}

~myclass()
{
while (threadsarestillrunning)
{
sleepsome();
}
}

while the above loop is executing, other threads that still hold a
pointer to myclass can safely access member variables and call methods,
right?

Sep 27 '06 #1
Share this Question
Share on Google+
9 Replies


P: n/a
Dilip wrote:
I do not want main() to return when myclass::runInfinitely() happens to
throw an exception without giving a chance for worker threads to die.

Currently I do it like this:

int main()
{
try
{
myclass myclassObj;
spawnthreads(&myclassObj);
myclass.runInfinitely();
}
catch(...)
{
}
}

~myclass()
{
while (threadsarestillrunning)
{
sleepsome();
}
}

while the above loop is executing, other threads that still hold a
pointer to myclass can safely access member variables and call methods,
right?
Syntactically, the code will work.

Logically, your threads own your object, not main(). Your threads should use
a shared_ptr (boost or tr1?), as each thread ends it releases a reference
count in this pointer. The last thread to end will trigger the pointer to
delete its pointee.

If you must go with the current design, use a reference counting semaphore
of some type, not a lazy loop. (Advice I frequently give myself!!) And your
threads should also guard access to this object based on a mutex semaphore.
So mutex + shared_ptr == reference counting semaphore...

Next, exceptions add a new screwball to the situation. Your code currently
defends stack unwinding, so your object lives long enough for other threads
to die, as the exception propagates in the main() thread. If those threads
don't know about the exception, they won't turn themselves off, so you may
have a race condition.

Throw and catch the exception, then trigger those threads, then let them
destroy the shared object.

--
Phlip
http://www.greencheese.us/ZeekLand <-- NOT a blog!!!
Sep 27 '06 #2

P: n/a
Phlip wrote:
Next, exceptions add a new screwball to the situation. Your code currently
defends stack unwinding, so your object lives long enough for other threads
to die, as the exception propagates in the main() thread. If those threads
don't know about the exception, they won't turn themselves off, so you may
have a race condition.
I can't use Boost (corporate policy and all). So I have a question
about what you said above. Why would the threads need to know whether
or not 'runInfinitely' threw an exception? They are just thread pool
threads -- they register themselves on creation with 'myclass' and
deregister themselves on finishing their work (these are all just
quickie jobs -- process some record and return). So when all threads
die, the deregistration mechanism effectively cleans out my
datastructure that I use to maintain a record of those threads.

So, in myclass's dtor, I wait around to see if the datastructure
becomes empty.. (for a reasonable amont of time).

I am not seeing the race condition you pointed out.

Sep 27 '06 #3

P: n/a
Dilip wrote:
Phlip wrote:
>Next, exceptions add a new screwball to the situation. Your code currently
defends stack unwinding, so your object lives long enough for other threads
to die, as the exception propagates in the main() thread. If those threads
don't know about the exception, they won't turn themselves off, so you may
have a race condition.

I can't use Boost (corporate policy and all).
Can you use std::tr1::shared_ptr? It's specified by an official ISO
technical report.

--

-- Pete

Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.
Sep 27 '06 #4

P: n/a
Pete Becker wrote:
Dilip wrote:
Phlip wrote:
Next, exceptions add a new screwball to the situation. Your code currently
defends stack unwinding, so your object lives long enough for other threads
to die, as the exception propagates in the main() thread. If those threads
don't know about the exception, they won't turn themselves off, so you may
have a race condition.
I can't use Boost (corporate policy and all).

Can you use std::tr1::shared_ptr? It's specified by an official ISO
technical report.
Left to me I am ready to devour Boost. The problem is unless tr1
supplied by Dinkumware is bundled along with a Visual Studio release, I
stand no chance of using all those cool facilities. I just saw a few
mins ago that Visual Studio 2005 has released Service Pack 1. If I
don't find it there I have to wait for the next release of their
compiler to access tr1.

Sep 27 '06 #5

P: n/a
Dilip wrote:
I just saw a few
mins ago that Visual Studio 2005 has released Service Pack 1. If I
don't find it there I have to wait for the next release of their
compiler to access tr1.
It's not there.

--

-- Pete

Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.
Sep 27 '06 #6

P: n/a
Dilip wrote:
int main()
{
try
{
myclass myclassObj;
spawnthreads(&myclassObj);
myclass.runInfinitely();
}
catch(...)
{
}
}

~myclass()
{
while (threadsarestillrunning)
{
sleepsome();
}
}
A note about the syntactic reason this is well-defined. If another thread
accesses myclassObj (and if a semaphore defends the object from concurrent
writes), then those threads access the object after control flow in this
thread has entered the destructor, but before encountering the closing
brace.

Only after this destructor starts calling its sub-destructors - after the
destructor body - do elements of the object start becoming unavailable.
Touching them will cause undefined behavior. So the threads can still freely
call methods on myclassObj, while its destructor is stuck in this holding
pattern.

However, if you inherit another object, and expect the loop in the parent
object's destructor to defend the child object's members, you are screwed!

--
Phlip
http://www.greencheese.us/ZeekLand <-- NOT a blog!!!
Sep 27 '06 #7

P: n/a
Dilip wrote:
Left to me I am ready to devour Boost. The problem is unless tr1
supplied by Dinkumware is bundled along with a Visual Studio release, I
stand no chance of using all those cool facilities. I just saw a few
mins ago that Visual Studio 2005 has released Service Pack 1. If I
don't find it there I have to wait for the next release of their
compiler to access tr1.
Google the source of shared_ptr, and just borrow it. If its contents depend
on other boosty things, whack them.

Writing your own shared pointer from scratch should be a nice coding
exercise, too!

--
Phlip
http://www.greencheese.us/ZeekLand <-- NOT a blog!!!
Sep 27 '06 #8

P: n/a
Phlip wrote:
Dilip wrote:
int main()
{
try
{
myclass myclassObj;
spawnthreads(&myclassObj);
myclass.runInfinitely();
}
catch(...)
{
}
}

~myclass()
{
while (threadsarestillrunning)
{
sleepsome();
}
}


Only after this destructor starts calling its sub-destructors - after the
destructor body - do elements of the object start becoming unavailable.
Touching them will cause undefined behavior. So the threads can still freely
call methods on myclassObj, while its destructor is stuck in this holding
pattern.
The above confirms what I suspected. Thanks Phlip for the vote of
confidence!

Sep 27 '06 #9

P: n/a
Dilip wrote:
The above confirms what I suspected. Thanks Phlip for the vote of
confidence!
Look up 'delete this'. That's a FAQ ("can I call 'delete this' safely?"),
and the answer is related. C++ defines the act of returning from a method
after its object goes bye-bye.

--
Phlip
http://www.greencheese.us/ZeekLand <-- NOT a blog!!!
Sep 27 '06 #10

This discussion thread is closed

Replies have been disabled for this discussion.