Re: How to properly exit a thread?



Sorry, for the quick repost, but I got curious and checked the source for Glib::Thread.
Unless I'm missing something, this looks to be the bit of importance:

File: glibmm/glib/src/thread.ccg

 try
 {
// Recreate the specific slot, and drop the reference obtained by create().
   (*static_cast<sigc::slot<void>*>(slot))();
 }
 catch(Glib::Thread::Exit&)
 {
   // Just exit from the thread.  The Thread::Exit exception
   // is our sane C++ replacement of g_thread_exit().
 }
 catch(...)
 {
   Glib::exception_handlers_invoke();
 }

And a note of interest in the docs:

http://www.gtkmm.org/docs/glibmm-2.4/docs/reference/html/classGlib_1_1Thread.html#_details

g_thread_exit() is not wrapped, because that function exits a thread without any cleanup. That's especially dangerous in C++ code, since the destructors of automatic objects won't be invoked. Instead, you can throw a Thread::Exit <http://www.gtkmm.org/docs/glibmm-2.4/docs/reference/html/classGlib_1_1Thread_1_1Exit.html> exception, which will be caught by the internal thread entry function.

So, this is what I've come up with. To me, the Glib::Thread::Exit seems to not really do a whole lot. Well, I suppose if you have some complicated thread working, and you're something like four levels down in different method calls, you could exit the thread by throwing this error and letting the stack unwind. Now, I've got mixed feelings on such a design, but it seems fairly much a design issue and not an API issue. Ie, if someone wanted to do something like this, they should implement it themselves. But I do realize its a grey area, and someone's probably got a better reason than what I came up with for having it.

And, I'm fairly intrigued about the notes about destructors not automatically being cleaned up after calling g_thread_exit().

Interesting find: In Stroustrup's book "The C++ Programing Language 3rd Edition" there's coverage of calling exit() (similar case to g_thread_exit() ) in Section 9.4.1.1 on page 218. Of specific interest, quoting: "Calling exit() means that the local variables of the calling function and its callers will not have their destructors invoked."

I never knew this.  Kinda makes you scratch your head and think.

Anyway, armed with my new knowledge that such conditions are "in the book" I'd think just not wrapping g_thread_exit would've been enough. But Glib::Thread:Exit adds some convenience to do things I wouldn't necessarily do myself.

So it would seem, functions like exit(), or g_thread_exit() don't allow destructors to be called because scope doesn't pass back out of the calling methods, and as a consequence, local variables don't get popped off the stack which in turn prevents normal destruction...

Cool.

Oh, and my earlier note about not calling return in your read_new_data() was incorrect. Unless I'm missing something, the only thing you can't do is call a non-returning function (g_thread_exit() ).

Oh, and to answer the original question:

throw Glib::Thread::Exit() ;

anywhere in the slot you pass to Glib::Thread::Create (FrameNode::read_new_data() ) is how you exit the thread.

Paul

Paul Davis wrote:

Xiangfei,

Docs indicate doing something like this:

void
FrameNode::read_new_data()
{
   bool done = false ;
   while( !done )
   {
      [do something]
   }

   throw Glib::Thread::Exit() ;
}

(Although, as a side note, and without looking at the Glib::Thread code and basing everything off of my guess as to how this is implemented, throw Glib::Thread::Exit() is optional at the end, and is probably meant as a way to exit the thread "early". Ie, don't call return ; Maybe someone with more experience on the Glib::Thread implementation coudl explain this a bit better, because it seems like an odd choice of implementation to me.)

What you've probably got at issue is guranteeing that all of your threads have exited before you attempt to close your program. My guess is that you've got a thread waiting on a condtion variable when an attempt to destroy the condition variable is made.

Without any more info on what your thread is doing, I can't really say much else.

As a side note, if you create your thread as joinable, read->join() will block until the thread exits. If you need to ensure that a thread has exited at some point in your software, this would be one method of doing so. (This is making some assumptions, like the spawned thread was required to finish before the spawning thread, if that makes any sense.) The more general method is using one of the normal synchronization constructs. Ie, a semaphore.

Hope that helps more than it confuses.

Paul


Xiangfei Jia wrote:

I created a thread like this:

Glib::Thread *const read = Glib::Thread::create(sigc::mem_fun(node, &FrameNode::read_new_data), false);

Sometimes, when I exit from my program I got this error message:
GThread-ERROR **: file gthread-posix.c: line 247 (): error 'Device or resource busy' during 'pthread_cond_destroy ((pthread_cond_t *) cond)'
aborting...
Aborted


I looked at the Glib reference, I found out I should use

throw Glib::Thread::Exit <http://www.gtkmm.org/docs/glibmm-2.4/docs/reference/html/classGlib_1_1Thread_1_1Exit.html>
();

to exit my thread. But I don't really know how to use this properly. Can anyone tell me how to use it please!!!!!

Thanks in advance!


Fei


------------------------------------------------------------------------

_______________________________________________
gtkmm-list mailing list
gtkmm-list gnome org
http://mail.gnome.org/mailman/listinfo/gtkmm-list
_______________________________________________
gtkmm-list mailing list
gtkmm-list gnome org
http://mail.gnome.org/mailman/listinfo/gtkmm-list




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]