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
, wxT("&Clear log\tCtrl-L"));
361 menuFile
->AppendSeparator();
362 menuFile
->Append(THREAD_QUIT
, wxT("E&xit\tAlt-X"));
363 menuBar
->Append(menuFile
, wxT("&File"));
365 wxMenu
*menuThread
= new wxMenu
;
366 menuThread
->Append(THREAD_START_THREAD
, wxT("&Start a new thread\tCtrl-N"));
367 menuThread
->Append(THREAD_START_THREADS
, wxT("Start &many threads at once"));
368 menuThread
->Append(THREAD_STOP_THREAD
, wxT("S&top the last spawned thread\tCtrl-S"));
369 menuThread
->AppendSeparator();
370 menuThread
->Append(THREAD_PAUSE_THREAD
, wxT("&Pause the last spawned running thread\tCtrl-P"));
371 menuThread
->Append(THREAD_RESUME_THREAD
, wxT("&Resume the first suspended thread\tCtrl-R"));
372 menuThread
->AppendSeparator();
373 menuThread
->Append(THREAD_START_WORKER
, wxT("Start a &worker thread\tCtrl-W"));
374 menuThread
->Append(THREAD_EXEC_MAIN
, wxT("&Launch a program from main thread\tF5"));
375 menuThread
->Append(THREAD_START_GUI_THREAD
, wxT("Launch a &GUI thread\tF6"));
376 menuBar
->Append(menuThread
, wxT("&Thread"));
378 wxMenu
*menuHelp
= new wxMenu
;
379 menuHelp
->Append(THREAD_SHOWCPUS
, wxT("&Show CPU count"));
380 menuHelp
->AppendSeparator();
381 menuHelp
->Append(THREAD_ABOUT
, wxT("&About..."));
382 menuBar
->Append(menuHelp
, wxT("&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(wxT("How many threads to start: "), wxT(""),
541 wxT("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(wxT("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(wxT("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(wxT("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(wxT("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
= wxT("Unknown number of CPUs");
704 msg
= wxT("WARNING: you're running without any CPUs!");
708 msg
= wxT("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 wxT("wxWidgets multithreaded application sample\n")
722 wxT("(c) 1998 Julian Smart, Guilhem Lavaux\n")
723 wxT("(c) 2000 Robert Roebling\n")
724 wxT("(c) 1999,2009 Vadim Zeitlin"),
725 wxT("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 wxT("Progress dialog"),
754 wxT("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 // we use this to check that disabling logging only affects the main thread
797 // but the messages from the worker thread will still be logged
799 wxLogMessage("You shouldn't see this message because of wxLogNull");
801 MyImageDialog
dlg(this);
807 // ----------------------------------------------------------------------------
809 // ----------------------------------------------------------------------------
811 BEGIN_EVENT_TABLE(MyImageDialog
, wxDialog
)
812 EVT_THREAD(GUITHREAD_EVENT
, MyImageDialog::OnGUIThreadEvent
)
813 EVT_PAINT(MyImageDialog::OnPaint
)
816 MyImageDialog::MyImageDialog(wxFrame
*parent
)
817 : wxDialog(parent
, wxID_ANY
, "Image created by a secondary thread",
818 wxDefaultPosition
, wxSize(GUITHREAD_BMP_SIZE
,GUITHREAD_BMP_SIZE
)*1.5, wxDEFAULT_DIALOG_STYLE
),
821 m_nCurrentProgress
= 0;
825 // NOTE: no need to lock m_csBmp until the thread isn't started:
828 if (!m_bmp
.Create(GUITHREAD_BMP_SIZE
,GUITHREAD_BMP_SIZE
) || !m_bmp
.IsOk())
830 wxLogError("Couldn't create the bitmap!");
835 wxMemoryDC
dc(m_bmp
);
836 dc
.SetBackground(*wxBLACK_BRUSH
);
839 // draw the bitmap from a secondary thread
840 if ( m_thread
.Create() != wxTHREAD_NO_ERROR
||
841 m_thread
.Run() != wxTHREAD_NO_ERROR
)
843 wxLogError(wxT("Can't create/run thread!"));
848 MyImageDialog::~MyImageDialog()
850 // in case our thread is still running and for some reason we are destroyed,
851 // do wait for the thread to complete as it assumes that its MyImageDialog
852 // pointer is always valid
856 void MyImageDialog::OnGUIThreadEvent(wxThreadEvent
& event
)
858 m_nCurrentProgress
= int(((float)event
.GetInt()*100)/GUITHREAD_NUM_UPDATES
);
863 void MyImageDialog::OnPaint(wxPaintEvent
& WXUNUSED(evt
))
867 const wxSize
& sz
= dc
.GetSize();
871 wxCriticalSectionLocker
locker(m_csBmp
);
872 dc
.DrawBitmap(m_bmp
, (sz
.GetWidth()-GUITHREAD_BMP_SIZE
)/2,
873 (sz
.GetHeight()-GUITHREAD_BMP_SIZE
)/2);
876 // paint a sort of progress bar with a 10px border:
877 dc
.SetBrush(*wxRED_BRUSH
);
878 dc
.DrawRectangle(10,10, m_nCurrentProgress
*(sz
.GetWidth()-20)/100,30);
879 dc
.SetTextForeground(*wxBLUE
);
880 dc
.DrawText(wxString::Format("%d%%", m_nCurrentProgress
),
881 (sz
.GetWidth()-dc
.GetCharWidth()*2)/2,
882 25-dc
.GetCharHeight()/2);
885 // ----------------------------------------------------------------------------
887 // ----------------------------------------------------------------------------
895 MyThread::~MyThread()
897 wxCriticalSectionLocker
locker(wxGetApp().m_critsect
);
899 wxArrayThread
& threads
= wxGetApp().m_threads
;
900 threads
.Remove(this);
902 if ( threads
.IsEmpty() )
904 // signal the main thread that there are no more threads left if it is
906 if ( wxGetApp().m_shuttingDown
)
908 wxGetApp().m_shuttingDown
= false;
910 wxGetApp().m_semAllDone
.Post();
915 wxThread::ExitCode
MyThread::Entry()
917 wxLogMessage("Thread started (priority = %u).", GetPriority());
919 for ( m_count
= 0; m_count
< 10; m_count
++ )
921 // check if the application is shutting down: in this case all threads
922 // should stop a.s.a.p.
924 wxCriticalSectionLocker
locker(wxGetApp().m_critsect
);
925 if ( wxGetApp().m_shuttingDown
)
929 // check if just this thread was asked to exit
933 wxLogMessage("Thread progress: %u", m_count
);
935 // wxSleep() can't be called from non-GUI thread!
936 wxThread::Sleep(1000);
939 wxLogMessage("Thread finished.");
945 // ----------------------------------------------------------------------------
947 // ----------------------------------------------------------------------------
949 // define this symbol to 1 to test if the YieldFor() call in the wxProgressDialog::Update
950 // function provokes a race condition in which the second wxThreadEvent posted by
951 // MyWorkerThread::Entry is processed by the YieldFor() call of wxProgressDialog::Update
952 // and results in the destruction of the progress dialog itself, resulting in a crash later.
953 #define TEST_YIELD_RACE_CONDITION 0
955 MyWorkerThread::MyWorkerThread(MyFrame
*frame
)
962 void MyWorkerThread::OnExit()
966 wxThread::ExitCode
MyWorkerThread::Entry()
968 #if TEST_YIELD_RACE_CONDITION
972 wxThreadEvent
event( wxEVT_COMMAND_THREAD
, WORKER_EVENT
);
975 wxQueueEvent( m_frame
, event
.Clone() );
978 wxQueueEvent( m_frame
, event
.Clone() );
980 for ( m_count
= 0; !m_frame
->Cancelled() && (m_count
< 100); m_count
++ )
982 // check if we were asked to exit
986 // create any type of command event here
987 wxThreadEvent
event( wxEVT_COMMAND_THREAD
, WORKER_EVENT
);
988 event
.SetInt( m_count
);
990 // send in a thread-safe way
991 wxQueueEvent( m_frame
, event
.Clone() );
996 wxThreadEvent
event( wxEVT_COMMAND_THREAD
, WORKER_EVENT
);
997 event
.SetInt(-1); // that's all
998 wxQueueEvent( m_frame
, event
.Clone() );
1005 // ----------------------------------------------------------------------------
1007 // ----------------------------------------------------------------------------
1009 wxThread::ExitCode
MyGUIThread::Entry()
1011 // uncomment this to check that disabling logging here does disable it for
1012 // this thread -- but not the main one if you also comment out wxLogNull
1013 // line in MyFrame::OnStartGUIThread()
1016 // this goes to the main window
1017 wxLogMessage("GUI thread starting");
1019 // use a thread-specific log target for this thread to show that its
1020 // messages don't appear in the main window while it runs
1022 wxLog::SetThreadActiveTarget(&logBuf
);
1024 for (int i
=0; i
<GUITHREAD_NUM_UPDATES
&& !TestDestroy(); i
++)
1026 // inform the GUI toolkit that we're going to use GUI functions
1027 // from a secondary thread:
1031 wxCriticalSectionLocker
lock(m_dlg
->m_csBmp
);
1033 // draw some more stuff on the bitmap
1034 wxMemoryDC
dc(m_dlg
->m_bmp
);
1035 dc
.SetBrush((i%2
)==0 ? *wxBLUE_BRUSH
: *wxGREEN_BRUSH
);
1036 dc
.DrawRectangle(rand()%GUITHREAD_BMP_SIZE
, rand()%GUITHREAD_BMP_SIZE
, 30, 30);
1038 // simulate long drawing time:
1042 // if we don't release the GUI mutex the MyImageDialog won't be able to refresh
1045 // notify the dialog that another piece of our masterpiece is complete:
1046 wxThreadEvent
event( wxEVT_COMMAND_THREAD
, GUITHREAD_EVENT
);
1048 wxQueueEvent( m_dlg
, event
.Clone() );
1050 if ( !((i
+ 1) % 10) )
1052 // this message will go to the buffer
1053 wxLogMessage("Step #%d.", i
+ 1);
1056 // give the main thread the time to refresh before we lock the GUI mutex again
1057 // FIXME: find a better way to do this!
1061 // now remove the thread-specific thread target
1062 wxLog::SetThreadActiveTarget(NULL
);
1064 // so that this goes to the main window again
1065 wxLogMessage("GUI thread finished.");