wxMutex, wxCondition issues

Jason Dolan jayson.dolan at gmail.com
Mon Oct 1 10:38:10 PDT 2007


On Oct 1, 12:34 pm, Jason Dolan <jayson.do... at gmail.com> wrote:
> Ok, so I've added this output code to wxapp_install_idle_handler():
>
> #include
> <iostream>                                                     //JD
> void wxapp_install_idle_handler()
> {
>         std::cerr << ">>>>>>>>" << std::endl << "Entering idle
> handler..." << std::endl;                                //JD
>     if (wxTheApp == NULL)
>         return;
>
> #if wxUSE_THREADS
>     wxMutexLocker lock(gs_idleTagsMutex);
> #endif
>
>     // Don't install the handler if it's already installed. This test
> *MUST*
>     // be done when gs_idleTagsMutex is locked!
>     if (!g_isIdle)
>
> {                                                                   //
> JD
>         std::cerr << "g_isIdle is FALSE! leaving idle handler" <<
> std::endl << "<<<<<<<<<" << std::endl;        //JD
>         return;
>     }                                                                   //
> JD
>
>     // GD: this assert is raised when using the thread sample (which
> works)
>     //     so the test is probably not so easy. Can widget callbacks
> be
>     //     triggered from child threads and, if so, for which widgets?
>     // wxASSERT_MSG( wxThread::IsMain() || gs_WakeUpIdle, wxT("attempt
> to install idle handler from widget callback in child thread (should
> be exclusively from wxWakeUpIdle)") );
>
>     wxASSERT_MSG( wxTheApp->m_idleTag == 0, wxT("attempt to install
> idle handler twice") );
>
>     g_isIdle = false;
>
>     // This routine gets called by all event handlers
>     // indicating that the idle is over. It may also
>     // get called from other thread for sending events
>     // to the main thread (and processing these in
>     // idle time). Very low priority.
>     std::cerr << "m_idleTag was: " << wxTheApp->m_idleTag <<
> std::endl;         //JD
>     wxTheApp->m_idleTag = g_idle_add_full(G_PRIORITY_LOW,
> wxapp_idle_callback, NULL, NULL);
>     std::cerr << "m_idleTag is now: " << wxTheApp->m_idleTag <<
> std::endl;      //JD
>     std::cerr << "Leaving idle handler..." << std::endl << "<<<<<<<<<"
> << std::endl;   //JD
>
> }
>
> When I run my application, the point where it freezes looks like this:
>
> Post message to gui thread
>
> Entering idle handler...
> m_idleTag was: 0
> m_idleTag is now: 1196
> Leaving idle handler...
> <<<<<<<<<
>
> Entering idle handler...
> g_isIdle is FALSE! leaving idle handler
> <<<<<<<<<
> Starting to wait for event processing...
> ***Then it sits there waiting for me to wave my mouse over the
> window***
> ***
> ***
> ***<moused waved over window>****
>
> Entering idle handler...
> m_idleTag was: 0
> m_idleTag is now: 1278
> Leaving idle handler...
> <<<<<<<<<
>
> Entering idle handler...
> g_isIdle is FALSE! leaving idle handler
> <<<<<<<<<
>
> Entering idle handler...
> g_isIdle is FALSE! leaving idle handler
> <<<<<<<<<
>
> Entering idle handler...
> g_isIdle is FALSE! leaving idle handler
> <<<<<<<<<
>
> Entering idle handler...
> g_isIdle is FALSE! leaving idle handler
> <<<<<<<<<
>
> Entering idle handler...
> g_isIdle is FALSE! leaving idle handler
> <<<<<<<<<
> In WidgetControlHandler
> Event processing complete.
>
> So it appears to successfully wake up from idle, but it then goes back
> into an idle state.  Perhaps there is a race condition where the app
> becomes idle, we force it to become not idle, then it becomes idle
> again... THEN the event is posted to the queue?


Ok, to test the race condition theory I added
::wxMilliSleep(100);
::wxWakeUpIdle();
right after
::wxPostEvent(m_pWindow, ServerEvent);

And things seem to work.  (Adding ::wxWakeUpIdle() without the sleep
seemed to make it so that this situation came up a little less
frequently, but still very frequent).

Here is the whole function with the recent change:

// Worker thread function that recieves a message from the server and
relays that message to the GUI thread...
CORBA::Boolean PCC_WidgetControl::WidgetControl(const MessageObject
&msgIn, MessageObject_out msgOut )
{
        bool result = true;
        wxCommandEvent ServerEvent ( wxEVT_PCC_WidgetControl );

        // Create an instance of the outbound messageobject so that we
can
send a response back to the server...
        msgOut = new MessageObject_Out;

        // load our container object for sending to the event handler
        MessageObjectMsgContainer msgContainer;

        msgContainer.pmsgIn = &msgIn;
        msgContainer.pmsgOut = msgOut;

        // then load a pointer to the data into the event
        ServerEvent.SetClientData( (void *) &msgContainer );

        m_pMutex->Lock();

        // post the event
        cerr << "Post message to gui thread" << endl;
        ::wxPostEvent(m_pWindow, ServerEvent);
	::wxMilliSleep(100);
	::wxWakeUpIdle();

        // then wait for the event handler to catch the event,
        // process the data, change the data(if needed), call
        // wxCondition::Signal or wxCondition::Broadcast.
        cerr << "Starting to wait for event processing...\n";
        m_pCondition->Wait();
        cerr << "Event processing complete.\n";

        //msgOut should now hold any response data from the gui thread
        result = msgContainer.result;

        m_pMutex->Unlock();

        return result;
}

Unfortunately, this is not the answer because it is a GREAT
preformance hit on my application.  And besides, there is no promise
that using a sleep of 100 milliseconds will always resolve the race
condition.  Maybe I'll look at ::wxPostEvent next to see WHY the event
is not placed on the event queue before ::wxWakeUpIdle is called.







More information about the wx-users mailing list