wxTimer interrupts other event handler

This forum can be used to talk about general design strategies, new ideas and questions in general related to wxWidgets. If you feel your questions doesn't fit anywhere, put it here.
Post Reply
Raife
In need of some credit
In need of some credit
Posts: 2
Joined: Fri Apr 15, 2005 9:25 pm

wxTimer interrupts other event handler

Post by Raife » Fri Apr 15, 2005 9:57 pm

I'm new to wxWidgets and I'm writing some code to communicate with a remote device using wxMSW. The communication is abstracted such that the device might be connected via TCP/IP, USB, Serial, etc. The remote device only speaks when spoken to, so I have a function 'Send Request' that blocks the current thread (using an unknown delay method in an external library) for a specified amount of time (~100ms)

My application needs to do two things.
1: Poll the device at a specified interval (500-1000ms) using 'Send Request'
2: Respond to clicks of the app's buttons using 'Send Request'

My wxWidgets dialog-based application has a wxTimer member and an EVT_TIMER() event handler to manage the polling.

Polling the remote device works perfectly, until I click one of the buttons on the dialog. I can't explain how or why, but it's possible for my timer event handler to interrupt the button event handler while the button handler is waiting on a response from the device or waiting on a call to wxSleep() (wxSleep added only for testing purposes).

Here's the wxWidgets event table definition

BEGIN_EVENT_TABLE(StatusDlg, wxDialog)
EVT_INIT_DIALOG(StatusDlg::OnInitDialog)
EVT_TIMER(TIMER_ID, StatusDlg::OnTimer)
EVT_BUTTON(XRCID( "IDC_RESET" ), StatusDlg::OnReset )
END_EVENT_TABLE()

Both the OnTimer function and the OnReset function call the 'Send Request' function which blocks for I/O. I have verified that when the device crashes, OnTimer gets called before OnReset finishes. I added a call to wxSleep(10) to OnReset to force the button event handling thread to sleep for 10 seconds and set a break point on that line and on the following line. When the program execution stopped at the first breakpoint, I set another breakpoint at the start of OnTimer. After resuming the execution in OnReset, the debugger stopped in OnTimer. I cleared the breakpoint in OnTimer and resumed execution. After 10 seconds the program returned to the code in OnReset one line after wxSleep(10)!!

It's as though the timer event is being called from a second thread, however GetThreadId() from the Win32 API returns the same ThreadID in both functions. And attempts to use wxMutex and wxCriticalSection don't fix the problem, i'm assuming because it's the same thread.

I've also noted that when I add wxSleep(10) to the button event handler my wxDialog UI doesn't freeze. Any buttons that I click are delayed until the button event handler finishes (for example I can't close my dialog using the X for 10 seconds), but the dialog still repaints its contents and I can edit the text in the dialog's textbox! As though the painting / updating / text editing events are not queued with the button events (and also the wxTimer events, causing my problems)

I'm at a loss! Is there any kind of initialization problems that might cause this? How can a single thread do two things!? I must really be doing something wrong, but I can't figure out where it is.

Thanks for any help,
Mike

mtew
Earned a small fee
Earned a small fee
Posts: 12
Joined: Sun Apr 10, 2005 3:28 pm
Location: Durham NC, USA

Post by mtew » Tue Apr 19, 2005 3:49 pm

I'm not sure how you would work around the problem, but dialog boxes are 'model'. That is they shut down all the event handlers except the one associated with the active dialog box. It might be possible to derive a class from the dialog box class that re-enables selected event handlers so your polling can go one even when there is a dailog box active. You'd still have problems with existing dialog boxes like the one associated with selecting a file... I suspect that there may be a better way to do this.
MTEW

Raife
In need of some credit
In need of some credit
Posts: 2
Joined: Fri Apr 15, 2005 9:25 pm

Post by Raife » Tue Apr 19, 2005 7:23 pm

mtew, thanks for the response.

I think my problem is the reverse of what you're describing. But it might still be related to the way that I'm using wxDialog. The sample applications that I've tried all create a wxFrame first and then wxDialogs. I'm using a wxDialog for my top-level window, so it's the only window in my application, the only event queue, and it's also the event queue that's registered to handle the timer messages.

My problem is that when my one and only GUI thread blocks for IO, (presumably through Win32's ReadFile or wxSleep), events like wxTimerEvent keep getting processed. So it's that the modal dialog's event queue is processing too much, not that it's preventing processing.

I can see from the call stack that the wxTimer's Notify() function is being called from inside user32.dll. Which is where I would expect my code to block for synchronous I/O using ReadFile(). I'm just not sure what's causing the timer events to be processed or how to stop it.

My solution thus far has been to create a full fledged wxThread object to handle the polling instead of using timers. This allows me to synchronize access to 'Send Request' using a wxMutex between the polling thread and the GUI thread.

It seems like I should be able to use a wxTimer here and not have to go through the trouble of threading and synchronizing. But I can't figure out why or how the wxTimerEvents are getting processed.

Post Reply