From: Francesco Montorsi Date: Fri, 20 Feb 2009 11:56:43 +0000 (+0000) Subject: no real change; just reorder the sample putting all declarations together and all... X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/3186fa91077bbab9e6b3c4da10994d4f26b3ff73?ds=inline no real change; just reorder the sample putting all declarations together and all implementations together; move frame construction code in MyFrame ctor; add some comment about TEST_YIELD_RACE_CONDITIONsymbol git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@59052 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/samples/thread/thread.cpp b/samples/thread/thread.cpp index f5ec942d81..fefc3e333e 100644 --- a/samples/thread/thread.cpp +++ b/samples/thread/thread.cpp @@ -9,6 +9,14 @@ // Licence: wxWindows license ///////////////////////////////////////////////////////////////////////////// +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + // For compilers that support precompilation, includes "wx/wx.h". #include "wx/wxprec.h" @@ -27,11 +35,18 @@ #include "wx/thread.h" #include "wx/dynarray.h" #include "wx/numdlg.h" - #include "wx/progdlg.h" +// ---------------------------------------------------------------------------- +// resources +// ---------------------------------------------------------------------------- + #include "../sample.xpm" +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + // define this to use wxExecute in the exec tests, otherwise just use system #define USE_EXECUTE @@ -67,9 +82,6 @@ public: bool m_shuttingDown; }; -// Create a new application object -IMPLEMENT_APP(MyApp) - // Define a new frame type class MyFrame: public wxFrame { @@ -150,6 +162,10 @@ private: DECLARE_EVENT_TABLE() }; +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + // ID for the menu commands enum { @@ -196,70 +212,6 @@ public: MyFrame *m_frame; }; -MyThread::MyThread(MyFrame *frame) - : wxThread() -{ - m_count = 0; - m_frame = frame; -} - -MyThread::~MyThread() -{ - wxCriticalSectionLocker locker(wxGetApp().m_critsect); - - wxArrayThread& threads = wxGetApp().m_threads; - threads.Remove(this); - - if ( threads.IsEmpty() ) - { - // signal the main thread that there are no more threads left if it is - // waiting for us - if ( wxGetApp().m_shuttingDown ) - { - wxGetApp().m_shuttingDown = false; - - wxGetApp().m_semAllDone.Post(); - } - } -} - -void *MyThread::Entry() -{ - wxString text; - - text.Printf(wxT("Thread 0x%lx started (priority = %u).\n"), - GetId(), GetPriority()); - WriteText(text); - // wxLogMessage(text); -- test wxLog thread safeness - - for ( m_count = 0; m_count < 10; m_count++ ) - { - // check if the application is shutting down: in this case all threads - // should stop a.s.a.p. - { - wxCriticalSectionLocker locker(wxGetApp().m_critsect); - if ( wxGetApp().m_shuttingDown ) - return NULL; - } - - // check if just this thread was asked to exit - if ( TestDestroy() ) - break; - - text.Printf(wxT("[%u] Thread 0x%lx here.\n"), m_count, GetId()); - WriteText(text); - - // wxSleep() can't be called from non-GUI thread! - wxThread::Sleep(1000); - } - - text.Printf(wxT("Thread 0x%lx finished.\n"), GetId()); - WriteText(text); - // wxLogMessage(text); -- test wxLog thread safeness - - return NULL; -} - // ---------------------------------------------------------------------------- // worker thread // ---------------------------------------------------------------------------- @@ -281,57 +233,6 @@ public: unsigned m_count; }; -MyWorkerThread::MyWorkerThread(MyFrame *frame) - : wxThread() -{ - m_frame = frame; - m_count = 0; -} - -void MyWorkerThread::OnExit() -{ -} - -#define TEST_YIELD_RACE_CONDITION 0 - -void *MyWorkerThread::Entry() -{ -#if TEST_YIELD_RACE_CONDITION - if ( TestDestroy() ) - return NULL; - - wxThreadEvent event( wxEVT_COMMAND_THREAD, WORKER_EVENT ); - - event.SetInt( 50 ); - wxQueueEvent( m_frame, new wxThreadEvent(event) ); - - event.SetInt(-1); - wxQueueEvent( m_frame, new wxThreadEvent(event) ); -#else - for ( m_count = 0; !m_frame->Cancelled() && (m_count < 100); m_count++ ) - { - // check if we were asked to exit - if ( TestDestroy() ) - break; - - // create any type of command event here - wxThreadEvent event( wxEVT_COMMAND_THREAD, WORKER_EVENT ); - event.SetInt( m_count ); - - // send in a thread-safe way - wxQueueEvent( m_frame, new wxThreadEvent(event) ); - - wxMilliSleep(200); - } - - wxThreadEvent event( wxEVT_COMMAND_THREAD, WORKER_EVENT ); - event.SetInt(-1); // that's all - wxQueueEvent( m_frame, new wxThreadEvent(event) ); -#endif - - return NULL; -} - // ---------------------------------------------------------------------------- // a thread which simply calls wxExecute // ---------------------------------------------------------------------------- @@ -354,8 +255,45 @@ private: wxString m_command; }; -// ---------------------------------------------------------------------------- +// ============================================================================ // implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// the application class +// ---------------------------------------------------------------------------- + +// Create a new application object +IMPLEMENT_APP(MyApp) + +MyApp::MyApp() +{ + m_shuttingDown = false; +} + +// `Main program' equivalent, creating windows and returning main app frame +bool MyApp::OnInit() +{ + if ( !wxApp::OnInit() ) + return false; + + // uncomment this to get some debugging messages from the trace code + // on the console (or just set WXTRACE env variable to include "thread") + //wxLog::AddTraceMask("thread"); + + // Create the main frame window + MyFrame *frame = new MyFrame((wxFrame *)NULL, _T("wxWidgets threads sample"), + 50, 50, 450, 340); + SetTopWindow(frame); + + // Show the frame + frame->Show(true); + + return true; +} + +// ---------------------------------------------------------------------------- +// MyFrame // ---------------------------------------------------------------------------- BEGIN_EVENT_TABLE(MyFrame, wxFrame) @@ -381,24 +319,12 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_IDLE(MyFrame::OnIdle) END_EVENT_TABLE() -MyApp::MyApp() -{ - m_shuttingDown = false; -} - -// `Main program' equivalent, creating windows and returning main app frame -bool MyApp::OnInit() +// My frame constructor +MyFrame::MyFrame(wxFrame *frame, const wxString& title, + int x, int y, int w, int h) + : wxFrame(frame, wxID_ANY, title, wxPoint(x, y), wxSize(w, h)) { - if ( !wxApp::OnInit() ) - return false; - - // uncomment this to get some debugging messages from the trace code - // on the console (or just set WXTRACE env variable to include "thread") - //wxLog::AddTraceMask("thread"); - - // Create the main frame window - MyFrame *frame = new MyFrame((wxFrame *)NULL, _T("wxWidgets threads sample"), - 50, 50, 450, 340); + SetIcon(wxIcon(sample_xpm)); // Make a menubar wxMenuBar *menuBar = new wxMenuBar; @@ -431,22 +357,7 @@ bool MyApp::OnInit() menuHelp->Append(THREAD_ABOUT, _T("&About...")); menuBar->Append(menuHelp, _T("&Help")); - frame->SetMenuBar(menuBar); - - // Show the frame - frame->Show(true); - - SetTopWindow(frame); - - return true; -} - -// My frame constructor -MyFrame::MyFrame(wxFrame *frame, const wxString& title, - int x, int y, int w, int h) - : wxFrame(frame, wxID_ANY, title, wxPoint(x, y), wxSize(w, h)) -{ - SetIcon(wxIcon(sample_xpm)); + SetMenuBar(menuBar); m_nRunning = m_nCount = 0; @@ -803,3 +714,133 @@ bool MyFrame::Cancelled() return m_cancelled; } + + +// ---------------------------------------------------------------------------- +// MyThread +// ---------------------------------------------------------------------------- + +MyThread::MyThread(MyFrame *frame) + : wxThread() +{ + m_count = 0; + m_frame = frame; +} + +MyThread::~MyThread() +{ + wxCriticalSectionLocker locker(wxGetApp().m_critsect); + + wxArrayThread& threads = wxGetApp().m_threads; + threads.Remove(this); + + if ( threads.IsEmpty() ) + { + // signal the main thread that there are no more threads left if it is + // waiting for us + if ( wxGetApp().m_shuttingDown ) + { + wxGetApp().m_shuttingDown = false; + + wxGetApp().m_semAllDone.Post(); + } + } +} + +void *MyThread::Entry() +{ + wxString text; + + text.Printf(wxT("Thread 0x%lx started (priority = %u).\n"), + GetId(), GetPriority()); + WriteText(text); + // wxLogMessage(text); -- test wxLog thread safeness + + for ( m_count = 0; m_count < 10; m_count++ ) + { + // check if the application is shutting down: in this case all threads + // should stop a.s.a.p. + { + wxCriticalSectionLocker locker(wxGetApp().m_critsect); + if ( wxGetApp().m_shuttingDown ) + return NULL; + } + + // check if just this thread was asked to exit + if ( TestDestroy() ) + break; + + text.Printf(wxT("[%u] Thread 0x%lx here.\n"), m_count, GetId()); + WriteText(text); + + // wxSleep() can't be called from non-GUI thread! + wxThread::Sleep(1000); + } + + text.Printf(wxT("Thread 0x%lx finished.\n"), GetId()); + WriteText(text); + // wxLogMessage(text); -- test wxLog thread safeness + + return NULL; +} + + +// ---------------------------------------------------------------------------- +// MyWorkerThread +// ---------------------------------------------------------------------------- + +MyWorkerThread::MyWorkerThread(MyFrame *frame) + : wxThread() +{ + m_frame = frame; + m_count = 0; +} + +void MyWorkerThread::OnExit() +{ +} + +// define this symbol to 1 to test if the YieldFor() call in the wxProgressDialog::Update +// function provokes a race condition in which the second wxThreadEvent posted by +// MyWorkerThread::Entry is processed by the YieldFor() call of wxProgressDialog::Update +// and results in the destruction of the progress dialog itself, resulting in a crash later. +#define TEST_YIELD_RACE_CONDITION 0 + +void *MyWorkerThread::Entry() +{ +#if TEST_YIELD_RACE_CONDITION + if ( TestDestroy() ) + return NULL; + + wxThreadEvent event( wxEVT_COMMAND_THREAD, WORKER_EVENT ); + + event.SetInt( 50 ); + wxQueueEvent( m_frame, event.Clone() ); + + event.SetInt(-1); + wxQueueEvent( m_frame, event.Clone() ); +#else + for ( m_count = 0; !m_frame->Cancelled() && (m_count < 100); m_count++ ) + { + // check if we were asked to exit + if ( TestDestroy() ) + break; + + // create any type of command event here + wxThreadEvent event( wxEVT_COMMAND_THREAD, WORKER_EVENT ); + event.SetInt( m_count ); + + // send in a thread-safe way + wxQueueEvent( m_frame, event.Clone() ); + + wxMilliSleep(200); + } + + wxThreadEvent event( wxEVT_COMMAND_THREAD, WORKER_EVENT ); + event.SetInt(-1); // that's all + wxQueueEvent( m_frame, event.Clone() ); +#endif + + return NULL; +} +