1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxWidgets thread sample
4 // Author: Guilhem Lavaux, Vadim Zeitlin
8 // Copyright: (c) 1998-2009 wxWidgets team
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx/wx.h".
21 #include "wx/wxprec.h"
32 #error "This sample requires thread support!"
33 #endif // wxUSE_THREADS
35 #include "wx/thread.h"
36 #include "wx/dynarray.h"
37 #include "wx/numdlg.h"
38 #include "wx/progdlg.h"
40 // ----------------------------------------------------------------------------
42 // ----------------------------------------------------------------------------
44 #include "../sample.xpm"
46 // ----------------------------------------------------------------------------
48 // ----------------------------------------------------------------------------
50 // define this to use wxExecute in the exec tests, otherwise just use system
54 #define EXEC(cmd) wxExecute((cmd), wxEXEC_SYNC)
56 #define EXEC(cmd) system(cmd)
60 WX_DEFINE_ARRAY_PTR(wxThread
*, wxArrayThread
);
62 // ----------------------------------------------------------------------------
63 // the application object
64 // ----------------------------------------------------------------------------
66 class MyApp
: public wxApp
72 virtual bool OnInit();
74 // critical section protects access to all of the fields below
75 wxCriticalSection m_critsect
;
77 // all the threads currently alive - as soon as the thread terminates, it's
78 // removed from the array
79 wxArrayThread m_threads
;
81 // semaphore used to wait for the threads to exit, see MyFrame::OnQuit()
82 wxSemaphore m_semAllDone
;
84 // indicates that we're shutting down and all threads should exit
88 // ----------------------------------------------------------------------------
89 // the main application frame
90 // ----------------------------------------------------------------------------
92 class MyFrame
: public wxFrame
,
97 MyFrame(const wxString
& title
);
100 // accessors for MyWorkerThread (called in its context!)
104 virtual void DoLogRecord(wxLogLevel level
,
106 const wxLogRecordInfo
& info
);
112 void OnQuit(wxCommandEvent
& event
);
113 void OnClear(wxCommandEvent
& event
);
115 void OnStartThread(wxCommandEvent
& event
);
116 void OnStartThreads(wxCommandEvent
& event
);
117 void OnStopThread(wxCommandEvent
& event
);
118 void OnPauseThread(wxCommandEvent
& event
);
119 void OnResumeThread(wxCommandEvent
& event
);
121 void OnStartWorker(wxCommandEvent
& event
);
122 void OnExecMain(wxCommandEvent
& event
);
123 void OnStartGUIThread(wxCommandEvent
& event
);
125 void OnShowCPUs(wxCommandEvent
& event
);
126 void OnAbout(wxCommandEvent
& event
);
128 void OnIdle(wxIdleEvent
&event
);
129 void OnWorkerEvent(wxThreadEvent
& event
);
130 void OnUpdateWorker(wxUpdateUIEvent
& event
);
134 void DoLogLine(wxTextCtrl
*text
,
135 const wxString
& timestr
,
136 const wxString
& threadstr
,
137 const wxString
& msg
);
140 // thread helper functions
141 // -----------------------
143 // helper function - creates a new thread (but doesn't run it)
144 MyThread
*CreateThread();
146 // update display in our status bar: called during idle handling
147 void UpdateThreadStatus();
150 // internal variables
151 // ------------------
153 // just some place to put our messages in
154 wxTextCtrl
*m_txtctrl
;
156 // old log target, we replace it with one using m_txtctrl during this
160 // the array of pending messages to be displayed and the critical section
162 wxArrayString m_messages
;
163 wxCriticalSection m_csMessages
;
165 // remember the number of running threads and total number of threads
169 // the progress dialog which we show while worker thread is running
170 wxProgressDialog
*m_dlgProgress
;
172 // was the worker thread cancelled by user?
174 wxCriticalSection m_csCancelled
; // protects m_cancelled
176 DECLARE_EVENT_TABLE()
179 // ----------------------------------------------------------------------------
181 // ----------------------------------------------------------------------------
183 // ID for the menu commands
186 THREAD_QUIT
= wxID_EXIT
,
187 THREAD_ABOUT
= wxID_ABOUT
,
190 THREAD_START_THREAD
= 201,
191 THREAD_START_THREADS
,
194 THREAD_RESUME_THREAD
,
198 THREAD_START_GUI_THREAD
,
202 WORKER_EVENT
= wxID_HIGHEST
+1, // this one gets sent from MyWorkerThread
203 GUITHREAD_EVENT
// this one gets sent from MyGUIThread
206 // ----------------------------------------------------------------------------
208 // ----------------------------------------------------------------------------
210 class MyThread
: public wxThread
216 // thread execution starts here
217 virtual void *Entry();
223 // ----------------------------------------------------------------------------
225 // ----------------------------------------------------------------------------
227 class MyWorkerThread
: public wxThread
230 MyWorkerThread(MyFrame
*frame
);
232 // thread execution starts here
233 virtual void *Entry();
235 // called when the thread exits - whether it terminates normally or is
236 // stopped with Delete() (but not when it is Kill()ed!)
237 virtual void OnExit();
244 // ----------------------------------------------------------------------------
245 // a thread which executes GUI calls using wxMutexGuiEnter/Leave
246 // ----------------------------------------------------------------------------
248 #define GUITHREAD_BMP_SIZE 300
249 #define GUITHREAD_NUM_UPDATES 50
252 class MyGUIThread
: public wxThread
255 MyGUIThread(MyImageDialog
*dlg
) : wxThread(wxTHREAD_JOINABLE
)
260 virtual ExitCode
Entry();
263 MyImageDialog
*m_dlg
;
266 // ----------------------------------------------------------------------------
267 // an helper dialog used by MyFrame::OnStartGUIThread
268 // ----------------------------------------------------------------------------
270 class MyImageDialog
: public wxDialog
274 MyImageDialog(wxFrame
*frame
);
277 // stuff used by MyGUIThread:
278 wxBitmap m_bmp
; // the bitmap drawn by MyGUIThread
279 wxCriticalSection m_csBmp
; // protects m_bmp
282 void OnGUIThreadEvent(wxThreadEvent
& event
);
283 void OnPaint(wxPaintEvent
&);
285 MyGUIThread m_thread
;
286 int m_nCurrentProgress
;
288 DECLARE_EVENT_TABLE()
291 // ============================================================================
293 // ============================================================================
295 // ----------------------------------------------------------------------------
296 // the application class
297 // ----------------------------------------------------------------------------
299 // Create a new application object
304 m_shuttingDown
= false;
307 // `Main program' equivalent, creating windows and returning main app frame
310 if ( !wxApp::OnInit() )
313 // uncomment this to get some debugging messages from the trace code
314 // on the console (or just set WXTRACE env variable to include "thread")
315 wxLog::AddTraceMask("thread");
317 // Create the main frame window
318 new MyFrame("wxWidgets threads sample");
323 // ----------------------------------------------------------------------------
325 // ----------------------------------------------------------------------------
327 BEGIN_EVENT_TABLE(MyFrame
, wxFrame
)
328 EVT_MENU(THREAD_QUIT
, MyFrame::OnQuit
)
329 EVT_MENU(THREAD_CLEAR
, MyFrame::OnClear
)
330 EVT_MENU(THREAD_START_THREAD
, MyFrame::OnStartThread
)
331 EVT_MENU(THREAD_START_THREADS
, MyFrame::OnStartThreads
)
332 EVT_MENU(THREAD_STOP_THREAD
, MyFrame::OnStopThread
)
333 EVT_MENU(THREAD_PAUSE_THREAD
, MyFrame::OnPauseThread
)
334 EVT_MENU(THREAD_RESUME_THREAD
, MyFrame::OnResumeThread
)
336 EVT_MENU(THREAD_START_WORKER
, MyFrame::OnStartWorker
)
337 EVT_MENU(THREAD_EXEC_MAIN
, MyFrame::OnExecMain
)
338 EVT_MENU(THREAD_START_GUI_THREAD
, MyFrame::OnStartGUIThread
)
340 EVT_MENU(THREAD_SHOWCPUS
, MyFrame::OnShowCPUs
)
341 EVT_MENU(THREAD_ABOUT
, MyFrame::OnAbout
)
343 EVT_UPDATE_UI(THREAD_START_WORKER
, MyFrame::OnUpdateWorker
)
344 EVT_THREAD(WORKER_EVENT
, MyFrame::OnWorkerEvent
)
345 EVT_IDLE(MyFrame::OnIdle
)
348 // My frame constructor
349 MyFrame::MyFrame(const wxString
& title
)
350 : wxFrame(NULL
, wxID_ANY
, title
)
352 m_oldLogger
= wxLog::GetActiveTarget();
354 SetIcon(wxIcon(sample_xpm
));
357 wxMenuBar
*menuBar
= new wxMenuBar
;
359 wxMenu
*menuFile
= new wxMenu
;
360 menuFile
->Append(THREAD_CLEAR
, _T("&Clear log\tCtrl-L"));
361 menuFile
->AppendSeparator();
362 menuFile
->Append(THREAD_QUIT
, _T("E&xit\tAlt-X"));
363 menuBar
->Append(menuFile
, _T("&File"));
365 wxMenu
*menuThread
= new wxMenu
;
366 menuThread
->Append(THREAD_START_THREAD
, _T("&Start a new thread\tCtrl-N"));
367 menuThread
->Append(THREAD_START_THREADS
, _T("Start &many threads at once"));
368 menuThread
->Append(THREAD_STOP_THREAD
, _T("S&top the last spawned thread\tCtrl-S"));
369 menuThread
->AppendSeparator();
370 menuThread
->Append(THREAD_PAUSE_THREAD
, _T("&Pause the last spawned running thread\tCtrl-P"));
371 menuThread
->Append(THREAD_RESUME_THREAD
, _T("&Resume the first suspended thread\tCtrl-R"));
372 menuThread
->AppendSeparator();
373 menuThread
->Append(THREAD_START_WORKER
, _T("Start a &worker thread\tCtrl-W"));
374 menuThread
->Append(THREAD_EXEC_MAIN
, _T("&Launch a program from main thread\tF5"));
375 menuThread
->Append(THREAD_START_GUI_THREAD
, _T("Launch a &GUI thread\tF6"));
376 menuBar
->Append(menuThread
, _T("&Thread"));
378 wxMenu
*menuHelp
= new wxMenu
;
379 menuHelp
->Append(THREAD_SHOWCPUS
, _T("&Show CPU count"));
380 menuHelp
->AppendSeparator();
381 menuHelp
->Append(THREAD_ABOUT
, _T("&About..."));
382 menuBar
->Append(menuHelp
, _T("&Help"));
386 m_nRunning
= m_nCount
= 0;
388 m_dlgProgress
= NULL
;
392 #endif // wxUSE_STATUSBAR
394 // create the logging text control and a header showing the meaning of the
396 wxTextCtrl
*header
= new wxTextCtrl(this, wxID_ANY
, "",
397 wxDefaultPosition
, wxDefaultSize
,
399 DoLogLine(header
, " Time", " Thread", "Message");
400 m_txtctrl
= new wxTextCtrl(this, wxID_ANY
, "",
401 wxDefaultPosition
, wxDefaultSize
,
402 wxTE_MULTILINE
| wxTE_READONLY
);
403 wxLog::SetActiveTarget(this);
405 // use fixed width font to align output in nice columns
406 wxFont
font(wxNORMAL_FONT
->GetPointSize(), wxFONTFAMILY_TELETYPE
,
407 wxFONTSTYLE_NORMAL
, wxFONTWEIGHT_NORMAL
);
408 header
->SetFont(font
);
409 m_txtctrl
->SetFont(font
);
411 m_txtctrl
->SetFocus();
413 // layout and show the frame
414 wxBoxSizer
*sizer
= new wxBoxSizer(wxVERTICAL
);
415 sizer
->Add(header
, wxSizerFlags().Expand());
416 sizer
->Add(m_txtctrl
, wxSizerFlags(1).Expand());
425 wxLog::SetActiveTarget(m_oldLogger
);
427 // NB: although the OS will terminate all the threads anyhow when the main
428 // one exits, it's good practice to do it ourselves -- even if it's not
429 // completely trivial in this example
431 // tell all the threads to terminate: note that they can't terminate while
432 // we're deleting them because they will block in their OnExit() -- this is
433 // important as otherwise we might access invalid array elements
436 wxCriticalSectionLocker
locker(wxGetApp().m_critsect
);
438 // check if we have any threads running first
439 const wxArrayThread
& threads
= wxGetApp().m_threads
;
440 size_t count
= threads
.GetCount();
445 // set the flag indicating that all threads should exit
446 wxGetApp().m_shuttingDown
= true;
449 // now wait for them to really terminate
450 wxGetApp().m_semAllDone
.Wait();
454 MyFrame::DoLogLine(wxTextCtrl
*text
,
455 const wxString
& timestr
,
456 const wxString
& threadstr
,
459 text
->AppendText(wxString::Format("%9s %10s %s", timestr
, threadstr
, msg
));
463 MyFrame::DoLogRecord(wxLogLevel level
,
465 const wxLogRecordInfo
& info
)
467 // let the default GUI logger treat warnings and errors as they should be
468 // more noticeable than just another line in the log window and also trace
469 // messages as there may be too many of them
470 if ( level
<= wxLOG_Warning
|| level
== wxLOG_Trace
)
472 m_oldLogger
->LogRecord(level
, msg
, info
);
479 wxDateTime(info
.timestamp
).FormatISOTime(),
480 info
.threadId
== wxThread::GetMainId()
482 : wxString::Format("%x", info
.threadId
),
487 MyThread
*MyFrame::CreateThread()
489 MyThread
*thread
= new MyThread
;
491 if ( thread
->Create() != wxTHREAD_NO_ERROR
)
493 wxLogError(wxT("Can't create thread!"));
496 wxCriticalSectionLocker
enter(wxGetApp().m_critsect
);
497 wxGetApp().m_threads
.Add(thread
);
502 void MyFrame::UpdateThreadStatus()
504 wxCriticalSectionLocker
enter(wxGetApp().m_critsect
);
506 // update the counts of running/total threads
508 nCount
= wxGetApp().m_threads
.Count();
509 for ( size_t n
= 0; n
< nCount
; n
++ )
511 if ( wxGetApp().m_threads
[n
]->IsRunning() )
515 if ( nCount
!= m_nCount
|| nRunning
!= m_nRunning
)
517 m_nRunning
= nRunning
;
520 wxLogStatus(this, wxT("%u threads total, %u running."), unsigned(nCount
), unsigned(nRunning
));
522 //else: avoid flicker - don't print anything
525 bool MyFrame::Cancelled()
527 wxCriticalSectionLocker
lock(m_csCancelled
);
532 // ----------------------------------------------------------------------------
533 // MyFrame - event handlers
534 // ----------------------------------------------------------------------------
536 void MyFrame::OnStartThreads(wxCommandEvent
& WXUNUSED(event
) )
540 s_num
= wxGetNumberFromUser(_T("How many threads to start: "), _T(""),
541 _T("wxThread sample"), s_num
, 1, 10000, this);
549 unsigned count
= unsigned(s_num
), n
;
551 wxArrayThread threads
;
553 // first create them all...
554 for ( n
= 0; n
< count
; n
++ )
556 wxThread
*thr
= CreateThread();
558 // we want to show the effect of SetPriority(): the first thread will
559 // have the lowest priority, the second - the highest, all the rest
562 thr
->SetPriority(WXTHREAD_MIN_PRIORITY
);
564 thr
->SetPriority(WXTHREAD_MAX_PRIORITY
);
566 thr
->SetPriority(WXTHREAD_DEFAULT_PRIORITY
);
573 msg
.Printf(wxT("%d new threads created."), count
);
574 SetStatusText(msg
, 1);
575 #endif // wxUSE_STATUSBAR
577 // ...and then start them
578 for ( n
= 0; n
< count
; n
++ )
584 void MyFrame::OnStartThread(wxCommandEvent
& WXUNUSED(event
) )
586 MyThread
*thread
= CreateThread();
588 if ( thread
->Run() != wxTHREAD_NO_ERROR
)
590 wxLogError(wxT("Can't start thread!"));
594 SetStatusText(_T("New thread started."), 1);
595 #endif // wxUSE_STATUSBAR
598 void MyFrame::OnStopThread(wxCommandEvent
& WXUNUSED(event
) )
600 wxCriticalSectionLocker
enter(wxGetApp().m_critsect
);
602 // stop the last thread
603 if ( wxGetApp().m_threads
.IsEmpty() )
605 wxLogError(wxT("No thread to stop!"));
609 wxGetApp().m_threads
.Last()->Delete();
612 SetStatusText(_T("Last thread stopped."), 1);
613 #endif // wxUSE_STATUSBAR
617 void MyFrame::OnResumeThread(wxCommandEvent
& WXUNUSED(event
) )
619 wxCriticalSectionLocker
enter(wxGetApp().m_critsect
);
621 // resume first suspended thread
622 size_t n
= 0, count
= wxGetApp().m_threads
.Count();
623 while ( n
< count
&& !wxGetApp().m_threads
[n
]->IsPaused() )
628 wxLogError(wxT("No thread to resume!"));
632 wxGetApp().m_threads
[n
]->Resume();
635 SetStatusText(_T("Thread resumed."), 1);
636 #endif // wxUSE_STATUSBAR
640 void MyFrame::OnPauseThread(wxCommandEvent
& WXUNUSED(event
) )
642 wxCriticalSectionLocker
enter(wxGetApp().m_critsect
);
644 // pause last running thread
645 int n
= wxGetApp().m_threads
.Count() - 1;
646 while ( n
>= 0 && !wxGetApp().m_threads
[n
]->IsRunning() )
651 wxLogError(wxT("No thread to pause!"));
655 wxGetApp().m_threads
[n
]->Pause();
658 SetStatusText(_T("Thread paused."), 1);
659 #endif // wxUSE_STATUSBAR
663 void MyFrame::OnIdle(wxIdleEvent
& event
)
665 UpdateThreadStatus();
670 void MyFrame::OnQuit(wxCommandEvent
& WXUNUSED(event
) )
675 void MyFrame::OnExecMain(wxCommandEvent
& WXUNUSED(event
))
677 wxString cmd
= wxGetTextFromUser("Please enter the command to execute",
682 "/bin/echo \"Message from another process\"",
686 return; // user clicked cancel
688 wxLogMessage(wxT("The exit code from the main program is %ld"),
692 void MyFrame::OnShowCPUs(wxCommandEvent
& WXUNUSED(event
))
696 int nCPUs
= wxThread::GetCPUCount();
700 msg
= _T("Unknown number of CPUs");
704 msg
= _T("WARNING: you're running without any CPUs!");
708 msg
= _T("This system only has one CPU.");
712 msg
.Printf(wxT("This system has %d CPUs"), nCPUs
);
718 void MyFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
) )
720 wxMessageDialog
dialog(this,
721 _T("wxWidgets multithreaded application sample\n")
722 _T("(c) 1998 Julian Smart, Guilhem Lavaux\n")
723 _T("(c) 2000 Robert Roebling\n")
724 _T("(c) 1999,2009 Vadim Zeitlin"),
725 _T("About wxThread sample"),
726 wxOK
| wxICON_INFORMATION
);
731 void MyFrame::OnClear(wxCommandEvent
& WXUNUSED(event
))
736 void MyFrame::OnUpdateWorker(wxUpdateUIEvent
& event
)
738 event
.Enable( m_dlgProgress
== NULL
);
741 void MyFrame::OnStartWorker(wxCommandEvent
& WXUNUSED(event
))
743 MyWorkerThread
*thread
= new MyWorkerThread(this);
745 if ( thread
->Create() != wxTHREAD_NO_ERROR
)
747 wxLogError(wxT("Can't create thread!"));
751 m_dlgProgress
= new wxProgressDialog
753 _T("Progress dialog"),
754 _T("Wait until the thread terminates or press [Cancel]"),
760 wxPD_ESTIMATED_TIME
|
764 // thread is not running yet, no need for crit sect
770 void MyFrame::OnWorkerEvent(wxThreadEvent
& event
)
772 int n
= event
.GetInt();
775 m_dlgProgress
->Destroy();
776 m_dlgProgress
= (wxProgressDialog
*)NULL
;
778 // the dialog is aborted because the event came from another thread, so
779 // we may need to wake up the main event loop for the dialog to be
785 if ( !m_dlgProgress
->Update(n
) )
787 wxCriticalSectionLocker
lock(m_csCancelled
);
794 void MyFrame::OnStartGUIThread(wxCommandEvent
& WXUNUSED(event
))
796 MyImageDialog
dlg(this);
802 // ----------------------------------------------------------------------------
804 // ----------------------------------------------------------------------------
806 BEGIN_EVENT_TABLE(MyImageDialog
, wxDialog
)
807 EVT_THREAD(GUITHREAD_EVENT
, MyImageDialog::OnGUIThreadEvent
)
808 EVT_PAINT(MyImageDialog::OnPaint
)
811 MyImageDialog::MyImageDialog(wxFrame
*parent
)
812 : wxDialog(parent
, wxID_ANY
, "Image created by a secondary thread",
813 wxDefaultPosition
, wxSize(GUITHREAD_BMP_SIZE
,GUITHREAD_BMP_SIZE
)*1.5, wxDEFAULT_DIALOG_STYLE
),
816 m_nCurrentProgress
= 0;
820 // NOTE: no need to lock m_csBmp until the thread isn't started:
823 if (!m_bmp
.Create(GUITHREAD_BMP_SIZE
,GUITHREAD_BMP_SIZE
) || !m_bmp
.IsOk())
825 wxLogError("Couldn't create the bitmap!");
830 wxMemoryDC
dc(m_bmp
);
831 dc
.SetBackground(*wxBLACK_BRUSH
);
834 // draw the bitmap from a secondary thread
835 if ( m_thread
.Create() != wxTHREAD_NO_ERROR
||
836 m_thread
.Run() != wxTHREAD_NO_ERROR
)
838 wxLogError(wxT("Can't create/run thread!"));
843 MyImageDialog::~MyImageDialog()
845 // in case our thread is still running and for some reason we are destroyed,
846 // do wait for the thread to complete as it assumes that its MyImageDialog
847 // pointer is always valid
851 void MyImageDialog::OnGUIThreadEvent(wxThreadEvent
& event
)
853 m_nCurrentProgress
= int(((float)event
.GetInt()*100)/GUITHREAD_NUM_UPDATES
);
858 void MyImageDialog::OnPaint(wxPaintEvent
& WXUNUSED(evt
))
862 const wxSize
& sz
= dc
.GetSize();
866 wxCriticalSectionLocker
locker(m_csBmp
);
867 dc
.DrawBitmap(m_bmp
, (sz
.GetWidth()-GUITHREAD_BMP_SIZE
)/2,
868 (sz
.GetHeight()-GUITHREAD_BMP_SIZE
)/2);
871 // paint a sort of progress bar with a 10px border:
872 dc
.SetBrush(*wxRED_BRUSH
);
873 dc
.DrawRectangle(10,10, m_nCurrentProgress
*(sz
.GetWidth()-20)/100,30);
874 dc
.SetTextForeground(*wxBLUE
);
875 dc
.DrawText(wxString::Format("%d%%", m_nCurrentProgress
),
876 (sz
.GetWidth()-dc
.GetCharWidth()*2)/2,
877 25-dc
.GetCharHeight()/2);
880 // ----------------------------------------------------------------------------
882 // ----------------------------------------------------------------------------
890 MyThread::~MyThread()
892 wxCriticalSectionLocker
locker(wxGetApp().m_critsect
);
894 wxArrayThread
& threads
= wxGetApp().m_threads
;
895 threads
.Remove(this);
897 if ( threads
.IsEmpty() )
899 // signal the main thread that there are no more threads left if it is
901 if ( wxGetApp().m_shuttingDown
)
903 wxGetApp().m_shuttingDown
= false;
905 wxGetApp().m_semAllDone
.Post();
910 wxThread::ExitCode
MyThread::Entry()
912 wxLogMessage("Thread started (priority = %u).", GetPriority());
914 for ( m_count
= 0; m_count
< 10; m_count
++ )
916 // check if the application is shutting down: in this case all threads
917 // should stop a.s.a.p.
919 wxCriticalSectionLocker
locker(wxGetApp().m_critsect
);
920 if ( wxGetApp().m_shuttingDown
)
924 // check if just this thread was asked to exit
928 wxLogMessage("Thread progress: %u", m_count
);
930 // wxSleep() can't be called from non-GUI thread!
931 wxThread::Sleep(1000);
934 wxLogMessage("Thread finished.");
940 // ----------------------------------------------------------------------------
942 // ----------------------------------------------------------------------------
944 // define this symbol to 1 to test if the YieldFor() call in the wxProgressDialog::Update
945 // function provokes a race condition in which the second wxThreadEvent posted by
946 // MyWorkerThread::Entry is processed by the YieldFor() call of wxProgressDialog::Update
947 // and results in the destruction of the progress dialog itself, resulting in a crash later.
948 #define TEST_YIELD_RACE_CONDITION 0
950 MyWorkerThread::MyWorkerThread(MyFrame
*frame
)
957 void MyWorkerThread::OnExit()
961 wxThread::ExitCode
MyWorkerThread::Entry()
963 #if TEST_YIELD_RACE_CONDITION
967 wxThreadEvent
event( wxEVT_COMMAND_THREAD
, WORKER_EVENT
);
970 wxQueueEvent( m_frame
, event
.Clone() );
973 wxQueueEvent( m_frame
, event
.Clone() );
975 for ( m_count
= 0; !m_frame
->Cancelled() && (m_count
< 100); m_count
++ )
977 // check if we were asked to exit
981 // create any type of command event here
982 wxThreadEvent
event( wxEVT_COMMAND_THREAD
, WORKER_EVENT
);
983 event
.SetInt( m_count
);
985 // send in a thread-safe way
986 wxQueueEvent( m_frame
, event
.Clone() );
991 wxThreadEvent
event( wxEVT_COMMAND_THREAD
, WORKER_EVENT
);
992 event
.SetInt(-1); // that's all
993 wxQueueEvent( m_frame
, event
.Clone() );
1000 // ----------------------------------------------------------------------------
1002 // ----------------------------------------------------------------------------
1004 wxThread::ExitCode
MyGUIThread::Entry()
1006 // this goes to the main window
1007 wxLogMessage("GUI thread starting");
1009 // use a thread-specific log target for this thread to show that its
1010 // messages don't appear in the main window while it runs
1012 wxLog::SetThreadActiveTarget(&logBuf
);
1014 for (int i
=0; i
<GUITHREAD_NUM_UPDATES
&& !TestDestroy(); i
++)
1016 // inform the GUI toolkit that we're going to use GUI functions
1017 // from a secondary thread:
1021 wxCriticalSectionLocker
lock(m_dlg
->m_csBmp
);
1023 // draw some more stuff on the bitmap
1024 wxMemoryDC
dc(m_dlg
->m_bmp
);
1025 dc
.SetBrush((i%2
)==0 ? *wxBLUE_BRUSH
: *wxGREEN_BRUSH
);
1026 dc
.DrawRectangle(rand()%GUITHREAD_BMP_SIZE
, rand()%GUITHREAD_BMP_SIZE
, 30, 30);
1028 // simulate long drawing time:
1032 // if we don't release the GUI mutex the MyImageDialog won't be able to refresh
1035 // notify the dialog that another piece of our masterpiece is complete:
1036 wxThreadEvent
event( wxEVT_COMMAND_THREAD
, GUITHREAD_EVENT
);
1038 wxQueueEvent( m_dlg
, event
.Clone() );
1040 if ( !((i
+ 1) % 10) )
1042 // this message will go to the buffer
1043 wxLogMessage("Step #%d.", i
+ 1);
1046 // give the main thread the time to refresh before we lock the GUI mutex again
1047 // FIXME: find a better way to do this!
1051 // now remove the thread-specific thread target
1052 wxLog::SetThreadActiveTarget(NULL
);
1054 // so that this goes to the main window again
1055 wxLogMessage("GUI thread finished.");