Let's say we have a thread that makes the PC speaker beep periodically (i.e. beep beep beep). This thread is extremely simple:
Code: Select all
class BeeperThread : public wxThread {
public:
void *Entry()
{
for (;;)
{
PC_Speaker_Set_ON();
this->Sleep(300); /* Stay on for 300 milliseconds */
PC_Speaker_Set_OFF();
this->Sleep(1000); /* Stay off for 1 second */
}
}
};
After having started the Beeper, if you click the button again, the Beeper gets turned off, and then the text on the button changes back to "Turn On Beeper".
Here's the code in the main thread for the clicking of the button:
Code: Select all
void DialogMain::OnClickButton_ToggleBeeper(wxCommandEvent &event)
{
static BeeperThread *p_beeper_thread = 0;
if ( !p_beeper_thread ) /* To check if they clicked "Turn On" or "Turn off" */
{
/* They clicked "Turn On" */
p_beeper_thread = new Beeper_Thread;
if ( p_beeper_thread->Create() != wxTHREAD_NO_ERROR )
{
wxMessageBox(wxT("Thread Creation Failed"));
delete p_beeper_thread;
p_beeper_thread = 0;
return;
}
p_beeper_thread->SetPriority(WXTHREAD_MIN_PRIORITY);
if ( p_beeper_thread->Run() != wxTHREAD_NO_ERROR )
{
wxMessageBox(wxT("Thread Run Failed"));
delete p_beeper_thread;
p_beeper_thread = 0;
return;
}
/* If we reach here, everything went off without a hitch
and the beeper is running */
this->m_button_ToggleBeeper->SetLabel(wxT("Turn Off Beeper"));
}
else
{
/* They clicked "Turn Off" */
p_beeper_thread->Kill();
PC_Speaker_Set_OFF(); /* In case the PC Speaker was ON when the thread was killed */
delete p_beeper_thread;
p_beeper_thread = 0;
this->m_button_ToggleBeeper->SetLabel(wxT("Turn On Beeper"));
}
}
OK, I have questions.
1) If you look at the Entry function for my BeeperThread, you'll see that the thread just runs in an eternal loop and it never checks TestDestroy. Is it OK to write a thread like this in wxWidgets? Basically I want the thread to run forever until the Main thread kills it.
2) If you look at the code for when the user clicks "Turn Off Beeper", you'll see that I call the Kill member function on my Beeper_Thread object. Is this OK? I've heard that the Kill function can have bad consequences such as leaving the C Standard Library in an undefined state.
I realise that there is a simple solution to this problem. Within the "Entry" function, all I have to do is call the TestDestroy function upon each iteration of the loop. Then, from the main GUI thread, all I have to do is call the Delete member function on my Beeper Thread object.
So why don't I just do that? Well the thing is, I'm not working with a PC speaker at all -- I just gave that example because it's really simple and it gets my point across.
In actuality, the secondary thread I have running is an Ethernet network sniffer. It sniffs Ethernet frames from the network in an eternal loop as follows:
Code: Select all
void *Entry()
{
for (;;)
{
FrameInfo fi; /* Data type to store an Ethernet frame */
Recieve_Ethernet_Frame( &fi ); /* This reads a frame from the network */
Process_Ethernet_Frame( &fi ); /* This processes the Ethernet frame */
}
}
It's possible that this function could take 5 seconds, or 10 seconds, or 10 minutes to return if there's no traffic on the network!
If I were to edit the "eternal loop" above, and add a call to TestDestroy, then I would have the problem of the thread lingering... and lingering... and lingering... until the call to Receive_Ethernet_Frame returns. Only then would I be able to call TestDestroy and finally stop the thread.
So my situation can be summed up as:
1) I have a secondary thread which contains an eternal loop.
2) Inside this eternal loop, there's a call to a synchronous function which could take seconds or minutes to return.
3) The challenge is to be able to (safely) terminate this thread instantly from within the Main thread (by "instantly" I mean within 2 seconds or so).
So... any ideas?
Thanks a lot for your time if you read this far, I appreciate it.