X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/07f5b19a15a8664abad7b5176c0260aacbbbc174..f1567cddead054974c4a079ed8ee2c798ef998dc:/samples/thread/test.cpp diff --git a/samples/thread/test.cpp b/samples/thread/test.cpp index 8133847ac5..be40d23a60 100644 --- a/samples/thread/test.cpp +++ b/samples/thread/test.cpp @@ -38,6 +38,11 @@ #include "wx/dynarray.h" #include "wx/time.h" +#include "wx/progdlg.h" + +// uncomment this to get some debugging messages from the trace code +//#define TRACE + class MyThread; WX_DEFINE_ARRAY(wxThread *, wxArrayThread); @@ -69,6 +74,9 @@ public: // operations void WriteText(const wxString& text) { m_txtctrl->WriteText(text); } + // accessors for MyWorkerThread (called in its context!) + bool Cancelled(); + // callbacks void OnQuit(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); @@ -79,9 +87,10 @@ public: void OnStopThread(wxCommandEvent& event); void OnPauseThread(wxCommandEvent& event); void OnResumeThread(wxCommandEvent& event); - + void OnStartWorker(wxCommandEvent& event); void OnWorkerEvent(wxCommandEvent& event); + void OnUpdateWorker(wxUpdateUIEvent& event); void OnIdle(wxIdleEvent &event); @@ -95,6 +104,15 @@ private: // remember the number of running threads and total number of threads size_t m_nRunning, m_nCount; + // the progress dialog which we show while worker thread is running + wxProgressDialog *m_dlgProgress; + + // was the worker thread cancelled by user? + bool m_cancelled; + + // protects m_cancelled + wxCriticalSection m_critsectWork; + DECLARE_EVENT_TABLE() }; @@ -155,9 +173,8 @@ void MyThread::WriteText(const wxString& text) wxMutexGuiEnter(); msg << text; - m_frame->WriteText(msg); - + wxMutexGuiLeave(); } @@ -175,6 +192,7 @@ void *MyThread::Entry() text.Printf("Thread 0x%x started (priority = %d).\n", GetId(), GetPriority()); WriteText(text); + // wxLogMessage(text); -- test wxLog thread safeness for ( m_count = 0; m_count < 10; m_count++ ) { @@ -191,6 +209,7 @@ void *MyThread::Entry() text.Printf("Thread 0x%x finished.\n", GetId()); WriteText(text); + // wxLogMessage(text); -- test wxLog thread safeness return NULL; } @@ -229,30 +248,34 @@ void MyWorkerThread::OnExit() void *MyWorkerThread::Entry() { - for ( m_count = 0; m_count < 10; m_count++ ) + for ( m_count = 0; !m_frame->Cancelled() && (m_count < 100); m_count++ ) { // check if we were asked to exit if ( TestDestroy() ) break; - + wxString text; text.Printf("[%u] Thread 0x%x here!!", m_count, GetId()); - // create any type of command event here + // create any type of command event here wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, WORKER_EVENT ); - event.SetInt( WORKER_EVENT ); + event.SetInt( m_count ); event.SetString( text ); - + // send in a thread-safe way wxPostEvent( m_frame, event ); - + // same as: // m_frame->AddPendingEvent( event ); // wxSleep() can't be called from non-main thread! - wxThread::Sleep(1000); + wxThread::Sleep(200); } + wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, WORKER_EVENT ); + event.SetInt(-1); // that's all + wxPostEvent( m_frame, event ); + return NULL; } @@ -269,7 +292,8 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(TEST_STOP_THREAD, MyFrame::OnStopThread) EVT_MENU(TEST_PAUSE_THREAD, MyFrame::OnPauseThread) EVT_MENU(TEST_RESUME_THREAD, MyFrame::OnResumeThread) - + + EVT_UPDATE_UI(TEST_START_WORKER, MyFrame::OnUpdateWorker) EVT_MENU(TEST_START_WORKER, MyFrame::OnStartWorker) EVT_MENU(WORKER_EVENT, MyFrame::OnWorkerEvent) @@ -279,6 +303,10 @@ END_EVENT_TABLE() // `Main program' equivalent, creating windows and returning main app frame bool MyApp::OnInit() { +#ifdef TRACE + wxLog::AddTraceMask("thread"); +#endif + // Create the main frame window MyFrame *frame = new MyFrame((wxFrame *)NULL, "wxWindows threads sample", 50, 50, 450, 340); @@ -303,7 +331,7 @@ bool MyApp::OnInit() thread_menu->Append(TEST_RESUME_THREAD, "&Resume suspended thread\tCtrl-R"); thread_menu->AppendSeparator(); thread_menu->Append(TEST_START_WORKER, "Start &worker thread\tCtrl-W"); - + menu_bar->Append(thread_menu, "&Thread"); frame->SetMenuBar(menu_bar); @@ -322,6 +350,8 @@ MyFrame::MyFrame(wxFrame *frame, const wxString& title, { m_nRunning = m_nCount = 0; + m_dlgProgress = (wxProgressDialog *)NULL; + CreateStatusBar(2); m_txtctrl = new wxTextCtrl(this, -1, "", wxPoint(0, 0), wxSize(0, 0), @@ -404,15 +434,17 @@ void MyFrame::OnStartThread(wxCommandEvent& WXUNUSED(event) ) void MyFrame::OnStopThread(wxCommandEvent& WXUNUSED(event) ) { + wxGetApp().m_critsect.Enter(); + // stop the last thread if ( wxGetApp().m_threads.IsEmpty() ) { wxLogError("No thread to stop!"); + + wxGetApp().m_critsect.Leave(); } else { - wxGetApp().m_critsect.Enter(); - wxThread *thread = wxGetApp().m_threads.Last(); // it's important to leave critical section before calling Delete() @@ -515,9 +547,19 @@ void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event) ) void MyFrame::OnClear(wxCommandEvent& WXUNUSED(event)) { +#ifdef TRACE + // log a separator + wxLogTrace("-------- log window cleared --------"); +#endif + m_txtctrl->Clear(); } +void MyFrame::OnUpdateWorker(wxUpdateUIEvent& event) +{ + event.Enable( m_dlgProgress == NULL ); +} + void MyFrame::OnStartWorker(wxCommandEvent& WXUNUSED(event)) { MyWorkerThread *thread = new MyWorkerThread(this); @@ -526,14 +568,59 @@ void MyFrame::OnStartWorker(wxCommandEvent& WXUNUSED(event)) { wxLogError("Can't create thread!"); } - + + m_dlgProgress = new wxProgressDialog + ( + "Progress dialog", + "Wait until the thread terminates or press [Cancel]", + 100, + this, + wxPD_CAN_ABORT | + wxPD_APP_MODAL | + wxPD_ELAPSED_TIME | + wxPD_ESTIMATED_TIME | + wxPD_REMAINING_TIME + ); + + // thread is not running yet, no need for crit sect + m_cancelled = FALSE; + thread->Run(); } void MyFrame::OnWorkerEvent(wxCommandEvent& event) { +#if 0 WriteText( "Got message from worker thread: " ); WriteText( event.GetString() ); WriteText( "\n" ); +#else + int n = event.GetInt(); + if ( n == -1 ) + { + m_dlgProgress->Destroy(); + m_dlgProgress = (wxProgressDialog *)NULL; + + // the dialog is aborted because the event came from another thread, so + // we may need to wake up the main event loop for the dialog to be + // really closed + wxWakeUpIdle(); + } + else + { + if ( !m_dlgProgress->Update(n) ) + { + wxCriticalSectionLocker lock(m_critsectWork); + + m_cancelled = TRUE; + } + } +#endif } +bool MyFrame::Cancelled() +{ + wxCriticalSectionLocker lock(m_critsectWork); + + return m_cancelled; +}