1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxWidgets thread sample
4 // Author: Guilhem Lavaux, Vadim Zeitlin
8 // Copyright: (c) 1998-2009 wxWidgets team
9 // Licence: wxWindows licence
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
));
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("%lx", 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(wxPRIORITY_MIN
);
564 thr
->SetPriority(wxPRIORITY_MAX
);
566 thr
->SetPriority(wxPRIORITY_DEFAULT
);
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 wxThread
* toDelete
= NULL
;
602 wxCriticalSectionLocker
enter(wxGetApp().m_critsect
);
604 // stop the last thread
605 if ( wxGetApp().m_threads
.IsEmpty() )
607 wxLogError(wxT("No thread to stop!"));
611 toDelete
= wxGetApp().m_threads
.Last();
617 // This can still crash if the thread gets to delete itself
622 SetStatusText(wxT("Last thread stopped."), 1);
623 #endif // wxUSE_STATUSBAR
627 void MyFrame::OnResumeThread(wxCommandEvent
& WXUNUSED(event
) )
629 wxCriticalSectionLocker
enter(wxGetApp().m_critsect
);
631 // resume first suspended thread
632 size_t n
= 0, count
= wxGetApp().m_threads
.Count();
633 while ( n
< count
&& !wxGetApp().m_threads
[n
]->IsPaused() )
638 wxLogError(wxT("No thread to resume!"));
642 wxGetApp().m_threads
[n
]->Resume();
645 SetStatusText(wxT("Thread resumed."), 1);
646 #endif // wxUSE_STATUSBAR
650 void MyFrame::OnPauseThread(wxCommandEvent
& WXUNUSED(event
) )
652 wxCriticalSectionLocker
enter(wxGetApp().m_critsect
);
654 // pause last running thread
655 int n
= wxGetApp().m_threads
.Count() - 1;
656 while ( n
>= 0 && !wxGetApp().m_threads
[n
]->IsRunning() )
661 wxLogError(wxT("No thread to pause!"));
665 wxGetApp().m_threads
[n
]->Pause();
668 SetStatusText(wxT("Thread paused."), 1);
669 #endif // wxUSE_STATUSBAR
673 void MyFrame::OnIdle(wxIdleEvent
& event
)
675 UpdateThreadStatus();
680 void MyFrame::OnQuit(wxCommandEvent
& WXUNUSED(event
) )
685 void MyFrame::OnExecMain(wxCommandEvent
& WXUNUSED(event
))
687 wxString cmd
= wxGetTextFromUser("Please enter the command to execute",
692 "/bin/echo \"Message from another process\"",
696 return; // user clicked cancel
698 wxLogMessage(wxT("The exit code from the main program is %ld"),
702 void MyFrame::OnShowCPUs(wxCommandEvent
& WXUNUSED(event
))
706 int nCPUs
= wxThread::GetCPUCount();
710 msg
= wxT("Unknown number of CPUs");
714 msg
= wxT("WARNING: you're running without any CPUs!");
718 msg
= wxT("This system only has one CPU.");
722 msg
.Printf(wxT("This system has %d CPUs"), nCPUs
);
728 void MyFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
) )
730 wxMessageDialog
dialog(this,
731 wxT("wxWidgets multithreaded application sample\n")
732 wxT("(c) 1998 Julian Smart, Guilhem Lavaux\n")
733 wxT("(c) 2000 Robert Roebling\n")
734 wxT("(c) 1999,2009 Vadim Zeitlin"),
735 wxT("About wxThread sample"),
736 wxOK
| wxICON_INFORMATION
);
741 void MyFrame::OnClear(wxCommandEvent
& WXUNUSED(event
))
746 void MyFrame::OnUpdateWorker(wxUpdateUIEvent
& event
)
748 event
.Enable( m_dlgProgress
== NULL
);
751 void MyFrame::OnStartWorker(wxCommandEvent
& WXUNUSED(event
))
753 MyWorkerThread
*thread
= new MyWorkerThread(this);
755 if ( thread
->Create() != wxTHREAD_NO_ERROR
)
757 wxLogError(wxT("Can't create thread!"));
761 m_dlgProgress
= new wxProgressDialog
763 wxT("Progress dialog"),
764 wxT("Wait until the thread terminates or press [Cancel]"),
770 wxPD_ESTIMATED_TIME
|
774 // thread is not running yet, no need for crit sect
780 void MyFrame::OnWorkerEvent(wxThreadEvent
& event
)
782 int n
= event
.GetInt();
785 m_dlgProgress
->Destroy();
786 m_dlgProgress
= (wxProgressDialog
*)NULL
;
788 // the dialog is aborted because the event came from another thread, so
789 // we may need to wake up the main event loop for the dialog to be
795 if ( !m_dlgProgress
->Update(n
) )
797 wxCriticalSectionLocker
lock(m_csCancelled
);
804 void MyFrame::OnStartGUIThread(wxCommandEvent
& WXUNUSED(event
))
806 // we use this to check that disabling logging only affects the main thread
807 // but the messages from the worker thread will still be logged
809 wxLogMessage("You shouldn't see this message because of wxLogNull");
811 MyImageDialog
dlg(this);
817 // ----------------------------------------------------------------------------
819 // ----------------------------------------------------------------------------
821 BEGIN_EVENT_TABLE(MyImageDialog
, wxDialog
)
822 EVT_THREAD(GUITHREAD_EVENT
, MyImageDialog::OnGUIThreadEvent
)
823 EVT_PAINT(MyImageDialog::OnPaint
)
826 MyImageDialog::MyImageDialog(wxFrame
*parent
)
827 : wxDialog(parent
, wxID_ANY
, "Image created by a secondary thread",
828 wxDefaultPosition
, wxSize(GUITHREAD_BMP_SIZE
,GUITHREAD_BMP_SIZE
)*1.5, wxDEFAULT_DIALOG_STYLE
),
831 m_nCurrentProgress
= 0;
835 // NOTE: no need to lock m_csBmp until the thread isn't started:
838 if (!m_bmp
.Create(GUITHREAD_BMP_SIZE
,GUITHREAD_BMP_SIZE
) || !m_bmp
.IsOk())
840 wxLogError("Couldn't create the bitmap!");
845 wxMemoryDC
dc(m_bmp
);
846 dc
.SetBackground(*wxBLACK_BRUSH
);
849 // draw the bitmap from a secondary thread
850 if ( m_thread
.Create() != wxTHREAD_NO_ERROR
||
851 m_thread
.Run() != wxTHREAD_NO_ERROR
)
853 wxLogError(wxT("Can't create/run thread!"));
858 MyImageDialog::~MyImageDialog()
860 // in case our thread is still running and for some reason we are destroyed,
861 // do wait for the thread to complete as it assumes that its MyImageDialog
862 // pointer is always valid
866 void MyImageDialog::OnGUIThreadEvent(wxThreadEvent
& event
)
868 m_nCurrentProgress
= int(((float)event
.GetInt()*100)/GUITHREAD_NUM_UPDATES
);
873 void MyImageDialog::OnPaint(wxPaintEvent
& WXUNUSED(evt
))
877 const wxSize
& sz
= dc
.GetSize();
881 wxCriticalSectionLocker
locker(m_csBmp
);
882 dc
.DrawBitmap(m_bmp
, (sz
.GetWidth()-GUITHREAD_BMP_SIZE
)/2,
883 (sz
.GetHeight()-GUITHREAD_BMP_SIZE
)/2);
886 // paint a sort of progress bar with a 10px border:
887 dc
.SetBrush(*wxRED_BRUSH
);
888 dc
.DrawRectangle(10,10, m_nCurrentProgress
*(sz
.GetWidth()-20)/100,30);
889 dc
.SetTextForeground(*wxBLUE
);
890 dc
.DrawText(wxString::Format("%d%%", m_nCurrentProgress
),
891 (sz
.GetWidth()-dc
.GetCharWidth()*2)/2,
892 25-dc
.GetCharHeight()/2);
895 // ----------------------------------------------------------------------------
897 // ----------------------------------------------------------------------------
905 MyThread::~MyThread()
907 wxCriticalSectionLocker
locker(wxGetApp().m_critsect
);
909 wxArrayThread
& threads
= wxGetApp().m_threads
;
910 threads
.Remove(this);
912 if ( threads
.IsEmpty() )
914 // signal the main thread that there are no more threads left if it is
916 if ( wxGetApp().m_shuttingDown
)
918 wxGetApp().m_shuttingDown
= false;
920 wxGetApp().m_semAllDone
.Post();
925 wxThread::ExitCode
MyThread::Entry()
927 wxLogMessage("Thread started (priority = %u).", GetPriority());
929 for ( m_count
= 0; m_count
< 10; m_count
++ )
931 // check if the application is shutting down: in this case all threads
932 // should stop a.s.a.p.
934 wxCriticalSectionLocker
locker(wxGetApp().m_critsect
);
935 if ( wxGetApp().m_shuttingDown
)
939 // check if just this thread was asked to exit
943 wxLogMessage("Thread progress: %u", m_count
);
945 // wxSleep() can't be called from non-GUI thread!
946 wxThread::Sleep(1000);
949 wxLogMessage("Thread finished.");
955 // ----------------------------------------------------------------------------
957 // ----------------------------------------------------------------------------
959 // define this symbol to 1 to test if the YieldFor() call in the wxProgressDialog::Update
960 // function provokes a race condition in which the second wxThreadEvent posted by
961 // MyWorkerThread::Entry is processed by the YieldFor() call of wxProgressDialog::Update
962 // and results in the destruction of the progress dialog itself, resulting in a crash later.
963 #define TEST_YIELD_RACE_CONDITION 0
965 MyWorkerThread::MyWorkerThread(MyFrame
*frame
)
972 void MyWorkerThread::OnExit()
976 wxThread::ExitCode
MyWorkerThread::Entry()
978 #if TEST_YIELD_RACE_CONDITION
982 wxThreadEvent
event( wxEVT_THREAD
, WORKER_EVENT
);
985 wxQueueEvent( m_frame
, event
.Clone() );
988 wxQueueEvent( m_frame
, event
.Clone() );
990 for ( m_count
= 0; !m_frame
->Cancelled() && (m_count
< 100); m_count
++ )
992 // check if we were asked to exit
996 // create any type of command event here
997 wxThreadEvent
event( wxEVT_THREAD
, WORKER_EVENT
);
998 event
.SetInt( m_count
);
1000 // send in a thread-safe way
1001 wxQueueEvent( m_frame
, event
.Clone() );
1006 wxThreadEvent
event( wxEVT_THREAD
, WORKER_EVENT
);
1007 event
.SetInt(-1); // that's all
1008 wxQueueEvent( m_frame
, event
.Clone() );
1015 // ----------------------------------------------------------------------------
1017 // ----------------------------------------------------------------------------
1019 wxThread::ExitCode
MyGUIThread::Entry()
1021 // uncomment this to check that disabling logging here does disable it for
1022 // this thread -- but not the main one if you also comment out wxLogNull
1023 // line in MyFrame::OnStartGUIThread()
1026 // this goes to the main window
1027 wxLogMessage("GUI thread starting");
1029 // use a thread-specific log target for this thread to show that its
1030 // messages don't appear in the main window while it runs
1032 wxLog::SetThreadActiveTarget(&logBuf
);
1034 for (int i
=0; i
<GUITHREAD_NUM_UPDATES
&& !TestDestroy(); i
++)
1036 // inform the GUI toolkit that we're going to use GUI functions
1037 // from a secondary thread:
1041 wxCriticalSectionLocker
lock(m_dlg
->m_csBmp
);
1043 // draw some more stuff on the bitmap
1044 wxMemoryDC
dc(m_dlg
->m_bmp
);
1045 dc
.SetBrush((i%2
)==0 ? *wxBLUE_BRUSH
: *wxGREEN_BRUSH
);
1046 dc
.DrawRectangle(rand()%GUITHREAD_BMP_SIZE
, rand()%GUITHREAD_BMP_SIZE
, 30, 30);
1048 // simulate long drawing time:
1052 // if we don't release the GUI mutex the MyImageDialog won't be able to refresh
1055 // notify the dialog that another piece of our masterpiece is complete:
1056 wxThreadEvent
event( wxEVT_THREAD
, GUITHREAD_EVENT
);
1058 wxQueueEvent( m_dlg
, event
.Clone() );
1060 if ( !((i
+ 1) % 10) )
1062 // this message will go to the buffer
1063 wxLogMessage("Step #%d.", i
+ 1);
1066 // give the main thread the time to refresh before we lock the GUI mutex again
1067 // FIXME: find a better way to do this!
1071 // now remove the thread-specific thread target
1072 wxLog::SetThreadActiveTarget(NULL
);
1074 // so that this goes to the main window again
1075 wxLogMessage("GUI thread finished.");