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