do what we advise, not what we say is unsupported: don't log directly from worker threads to wxTextCtrl but do it from the idle handler of the main thread
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@54020 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
parent
cd1ff792d2
commit
3a105cbc3c
@ -80,14 +80,23 @@ public:
|
|||||||
MyFrame(wxFrame *frame, const wxString& title, int x, int y, int w, int h);
|
MyFrame(wxFrame *frame, const wxString& title, int x, int y, int w, int h);
|
||||||
virtual ~MyFrame();
|
virtual ~MyFrame();
|
||||||
|
|
||||||
// operations
|
// this function is MT-safe, i.e. it can be called from worker threads
|
||||||
void WriteText(const wxString& text) { m_txtctrl->WriteText(text); }
|
// safely without any additional locking
|
||||||
|
void LogThreadMessage(const wxString& text)
|
||||||
|
{
|
||||||
|
wxCriticalSectionLocker lock(m_csMessages);
|
||||||
|
m_messages.push_back(text);
|
||||||
|
|
||||||
|
// as we effectively log the messages from the idle event handler,
|
||||||
|
// ensure it's going to be called now that we have some messages to log
|
||||||
|
wxWakeUpIdle();
|
||||||
|
}
|
||||||
|
|
||||||
// accessors for MyWorkerThread (called in its context!)
|
// accessors for MyWorkerThread (called in its context!)
|
||||||
bool Cancelled();
|
bool Cancelled();
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
// callbacks
|
// event handlers
|
||||||
void OnQuit(wxCommandEvent& event);
|
void OnQuit(wxCommandEvent& event);
|
||||||
void OnClear(wxCommandEvent& event);
|
void OnClear(wxCommandEvent& event);
|
||||||
|
|
||||||
@ -109,15 +118,27 @@ protected:
|
|||||||
|
|
||||||
void OnIdle(wxIdleEvent &event);
|
void OnIdle(wxIdleEvent &event);
|
||||||
|
|
||||||
private:
|
|
||||||
// helper function - creates a new thread (but doesn't run it)
|
// helper function - creates a new thread (but doesn't run it)
|
||||||
MyThread *CreateThread();
|
MyThread *CreateThread();
|
||||||
|
|
||||||
|
// update display in our status bar: called during idle handling
|
||||||
|
void UpdateThreadStatus();
|
||||||
|
|
||||||
|
// log the messages queued by LogThreadMessage()
|
||||||
|
void DoLogThreadMessages();
|
||||||
|
|
||||||
|
|
||||||
// just some place to put our messages in
|
// just some place to put our messages in
|
||||||
wxTextCtrl *m_txtctrl;
|
wxTextCtrl *m_txtctrl;
|
||||||
|
|
||||||
|
// the array of pending messages to be displayed and the critical section
|
||||||
|
// protecting it
|
||||||
|
wxArrayString m_messages;
|
||||||
|
wxCriticalSection m_csMessages;
|
||||||
|
|
||||||
// remember the number of running threads and total number of threads
|
// remember the number of running threads and total number of threads
|
||||||
size_t m_nRunning, m_nCount;
|
size_t m_nRunning,
|
||||||
|
m_nCount;
|
||||||
|
|
||||||
// the progress dialog which we show while worker thread is running
|
// the progress dialog which we show while worker thread is running
|
||||||
wxProgressDialog *m_dlgProgress;
|
wxProgressDialog *m_dlgProgress;
|
||||||
@ -186,17 +207,7 @@ MyThread::MyThread(MyFrame *frame)
|
|||||||
|
|
||||||
void MyThread::WriteText(const wxString& text)
|
void MyThread::WriteText(const wxString& text)
|
||||||
{
|
{
|
||||||
wxString msg;
|
m_frame->LogThreadMessage(text);
|
||||||
|
|
||||||
// before doing any GUI calls we must ensure that this thread is the only
|
|
||||||
// one doing it!
|
|
||||||
|
|
||||||
wxMutexGuiEnter();
|
|
||||||
|
|
||||||
msg << text;
|
|
||||||
m_frame->WriteText(msg);
|
|
||||||
|
|
||||||
wxMutexGuiLeave();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyThread::OnExit()
|
void MyThread::OnExit()
|
||||||
@ -295,8 +306,7 @@ void *MyWorkerThread::Entry()
|
|||||||
// send in a thread-safe way
|
// send in a thread-safe way
|
||||||
wxPostEvent( m_frame, event );
|
wxPostEvent( m_frame, event );
|
||||||
|
|
||||||
// wxSleep() can't be called from non-main thread!
|
wxMilliSleep(200);
|
||||||
wxThread::Sleep(200);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, WORKER_EVENT );
|
wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, WORKER_EVENT );
|
||||||
@ -631,8 +641,29 @@ void MyFrame::OnPauseThread(wxCommandEvent& WXUNUSED(event) )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the frame title indicating the current number of threads
|
|
||||||
void MyFrame::OnIdle(wxIdleEvent& event)
|
void MyFrame::OnIdle(wxIdleEvent& event)
|
||||||
|
{
|
||||||
|
DoLogThreadMessages();
|
||||||
|
|
||||||
|
UpdateThreadStatus();
|
||||||
|
|
||||||
|
event.Skip();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyFrame::DoLogThreadMessages()
|
||||||
|
{
|
||||||
|
wxCriticalSectionLocker lock(m_csMessages);
|
||||||
|
|
||||||
|
const size_t count = m_messages.size();
|
||||||
|
for ( size_t n = 0; n < count; n++ )
|
||||||
|
{
|
||||||
|
m_txtctrl->AppendText(m_messages[n]);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_messages.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyFrame::UpdateThreadStatus()
|
||||||
{
|
{
|
||||||
wxCriticalSectionLocker enter(wxGetApp().m_critsect);
|
wxCriticalSectionLocker enter(wxGetApp().m_critsect);
|
||||||
|
|
||||||
@ -653,8 +684,6 @@ void MyFrame::OnIdle(wxIdleEvent& event)
|
|||||||
wxLogStatus(this, wxT("%u threads total, %u running."), unsigned(nCount), unsigned(nRunning));
|
wxLogStatus(this, wxT("%u threads total, %u running."), unsigned(nCount), unsigned(nRunning));
|
||||||
}
|
}
|
||||||
//else: avoid flicker - don't print anything
|
//else: avoid flicker - don't print anything
|
||||||
|
|
||||||
event.Skip();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event) )
|
void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event) )
|
||||||
@ -757,11 +786,6 @@ void MyFrame::OnStartWorker(wxCommandEvent& WXUNUSED(event))
|
|||||||
|
|
||||||
void MyFrame::OnWorkerEvent(wxCommandEvent& event)
|
void MyFrame::OnWorkerEvent(wxCommandEvent& event)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
WriteText( _T("Got message from worker thread: ") );
|
|
||||||
WriteText( event.GetString() );
|
|
||||||
WriteText( _T("\n") );
|
|
||||||
#else
|
|
||||||
int n = event.GetInt();
|
int n = event.GetInt();
|
||||||
if ( n == -1 )
|
if ( n == -1 )
|
||||||
{
|
{
|
||||||
@ -782,7 +806,6 @@ void MyFrame::OnWorkerEvent(wxCommandEvent& event)
|
|||||||
m_cancelled = true;
|
m_cancelled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MyFrame::Cancelled()
|
bool MyFrame::Cancelled()
|
||||||
|
Loading…
Reference in New Issue
Block a user