Re: Attaching an event source to a GMainLoop in a thread



On Sunday 03 December 2006 20:34, Braden McDaniel wrote:
[snip]
On Sun, 2006-12-03 at 19:05 +0000, Chris Vine wrote:
Wouldn't unreferencing main_context cause it to be freed?  (And does
g_main_loop_run() increement the reference count of main_loop?  If not
then unreferencing main_loop that will also destroy the main loop).  The
call to g_source_unref() is correct (g_source_attach will increment the
reference count of quit).

I'm not getting past the call to g_main_loop_run, so the *_unref calls
aren't the problem.

I've gotten closer to the problem; but it's just mysteriouser.

The callback looks like this:

        gboolean openvrml_player_command_channel_loop_quit_event(const
gpointer data) {
            GMainLoop * const main_loop = static_cast<GMainLoop *>(data);

            if (::quit_flag.value()) {
                g_main_loop_quit(main_loop);
                return false;
            }
            return true;
        }

quit_flag is just a boolean flag protected by a mutex:

        class flag : boost::noncopyable {
            mutable boost::mutex mutex_;
            bool value_;

        public:
            flag(bool init = false);

            bool value() const;
            void value(bool val);
        };

It appears that the core dump happens in the first call to
openvrml_player_command_channel_loop_quit_event. But here things get
murky because the problem seems to be very timing-sensitive. If I put a
print statement at the beginning of
openvrml_player_command_channel_loop_quit_event, it starts working. And
if I instead put a print statement at the beginning of flag::value(), it
starts working.

This points, I think, to something being wrong with the state of
quit_flag at the time I try to use it in
openvrml_player_command_channel_loop_quit_event--like it's not fully
initialized. Though I don't understand why that would be the case--my
thread is being started from main() quit_flag is a global variable (in
the same translation unit as main()).

Yes, I see, it is not the dereferencing which is the problem, which is 
correct.

Have you called g_thread_init() - the glib main loop is not thread safe 
otherwise?  Apart from that, the symptoms you report point to a memory 
visibility issue, but since the only variable other than flag which is used 
in the callback is the data element (cast back to GMailLoop*) which is 
initialised in the same thread as the one in which the callback is running, 
it looks as if it is the flag.  However, that doesn't seem right either if 
the flag object is global and so constructed before the new thread which 
creates the GMainContext and GMainLoop objects starts, since access to the 
flag value is protected by a mutex so visibility is guaranteed.

Incidentally, your idle handler will form a busy loop if it sits doing nothing 
except checking the value of the flag.  As your idle handler, and so your new 
thread, does nothing except spin on a flag I assume you have just provided it 
as a test case: however if you want to wait on another thread like that you 
should really use a condition variable rather than a busy loop.  ("Idle" 
handler is a bit of a misnomer - it is only an idle handler if it always 
returns false and so fires only once - it is only "idle" in the sense that is 
has a lower priority in the loop calling order than some other callbacks.)

If you are using gcc it won't be an issue but the callback should have C not 
C++ linkage (ie be declared extern "C").

Chris




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