1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxWidgets thread sample
4 // Author: Guilhem Lavaux, Vadim Zeitlin
7 // Copyright: (c) 1998-2009 wxWidgets team
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // For compilers that support precompilation, includes "wx/wx.h".
20 #include "wx/wxprec.h"
31 #error "This sample requires thread support!"
32 #endif // wxUSE_THREADS
34 #include "wx/thread.h"
35 #include "wx/dynarray.h"
36 #include "wx/numdlg.h"
37 #include "wx/progdlg.h"
39 // ----------------------------------------------------------------------------
41 // ----------------------------------------------------------------------------
43 #include "../sample.xpm"
45 // ----------------------------------------------------------------------------
47 // ----------------------------------------------------------------------------
49 // define this to use wxExecute in the exec tests, otherwise just use system
53 #define EXEC(cmd) wxExecute((cmd), wxEXEC_SYNC)
55 #define EXEC(cmd) system(cmd)
59 WX_DEFINE_ARRAY_PTR(wxThread
*, wxArrayThread
);
61 // ----------------------------------------------------------------------------
62 // the application object
63 // ----------------------------------------------------------------------------
65 class MyApp
: public wxApp
71 virtual bool OnInit();
73 // critical section protects access to all of the fields below
74 wxCriticalSection m_critsect
;
76 // all the threads currently alive - as soon as the thread terminates, it's
77 // removed from the array
78 wxArrayThread m_threads
;
80 // semaphore used to wait for the threads to exit, see MyFrame::OnQuit()
81 wxSemaphore m_semAllDone
;
83 // indicates that we're shutting down and all threads should exit
87 // ----------------------------------------------------------------------------
88 // the main application frame
89 // ----------------------------------------------------------------------------
91 class MyFrame
: public wxFrame
,
96 MyFrame(const wxString
& title
);
99 // accessors for MyWorkerThread (called in its context!)
103 virtual void DoLogRecord(wxLogLevel level
,
105 const wxLogRecordInfo
& info
);
111 void OnQuit(wxCommandEvent
& event
);
112 void OnClear(wxCommandEvent
& event
);
114 void OnStartThread(wxCommandEvent
& event
);
115 void OnStartThreads(wxCommandEvent
& event
);
116 void OnStopThread(wxCommandEvent
& event
);
117 void OnPauseThread(wxCommandEvent
& event
);
118 void OnResumeThread(wxCommandEvent
& event
);
120 void OnStartWorker(wxCommandEvent
& event
);
121 void OnExecMain(wxCommandEvent
& event
);
122 void OnStartGUIThread(wxCommandEvent
& event
);
124 void OnShowCPUs(wxCommandEvent
& event
);
125 void OnAbout(wxCommandEvent
& event
);
127 void OnIdle(wxIdleEvent
&event
);
128 void OnWorkerEvent(wxThreadEvent
& event
);
129 void OnUpdateWorker(wxUpdateUIEvent
& event
);
133 void DoLogLine(wxTextCtrl
*text
,
134 const wxString
& timestr
,
135 const wxString
& threadstr
,
136 const wxString
& msg
);
139 // thread helper functions
140 // -----------------------
142 // helper function - creates a new thread (but doesn't run it)
143 MyThread
*CreateThread();
145 // update display in our status bar: called during idle handling
146 void UpdateThreadStatus();
149 // internal variables
150 // ------------------
152 // just some place to put our messages in
153 wxTextCtrl
*m_txtctrl
;
155 // old log target, we replace it with one using m_txtctrl during this
159 // the array of pending messages to be displayed and the critical section
161 wxArrayString m_messages
;
162 wxCriticalSection m_csMessages
;
164 // remember the number of running threads and total number of threads
168 // the progress dialog which we show while worker thread is running
169 wxProgressDialog
*m_dlgProgress
;
171 // was the worker thread cancelled by user?
173 wxCriticalSection m_csCancelled
; // protects m_cancelled
175 DECLARE_EVENT_TABLE()
178 // ----------------------------------------------------------------------------
180 // ----------------------------------------------------------------------------
182 // ID for the menu commands
185 THREAD_QUIT
= wxID_EXIT
,
186 THREAD_ABOUT
= wxID_ABOUT
,
189 THREAD_START_THREAD
= 201,
190 THREAD_START_THREADS
,
193 THREAD_RESUME_THREAD
,
197 THREAD_START_GUI_THREAD
,
201 WORKER_EVENT
= wxID_HIGHEST
+1, // this one gets sent from MyWorkerThread
202 GUITHREAD_EVENT
// this one gets sent from MyGUIThread
205 // ----------------------------------------------------------------------------
207 // ----------------------------------------------------------------------------
209 class MyThread
: public wxThread
215 // thread execution starts here
216 virtual void *Entry();
222 // ----------------------------------------------------------------------------
224 // ----------------------------------------------------------------------------
226 class MyWorkerThread
: public wxThread
229 MyWorkerThread(MyFrame
*frame
);
231 // thread execution starts here
232 virtual void *Entry();
234 // called when the thread exits - whether it terminates normally or is
235 // stopped with Delete() (but not when it is Kill()ed!)
236 virtual void OnExit();
243 // ----------------------------------------------------------------------------
244 // a thread which executes GUI calls using wxMutexGuiEnter/Leave
245 // ----------------------------------------------------------------------------
247 #define GUITHREAD_BMP_SIZE 300
248 #define GUITHREAD_NUM_UPDATES 50
251 class MyGUIThread
: public wxThread
254 MyGUIThread(MyImageDialog
*dlg
) : wxThread(wxTHREAD_JOINABLE
)
259 virtual ExitCode
Entry();
262 MyImageDialog
*m_dlg
;
265 // ----------------------------------------------------------------------------
266 // an helper dialog used by MyFrame::OnStartGUIThread
267 // ----------------------------------------------------------------------------
269 class MyImageDialog
: public wxDialog
273 MyImageDialog(wxFrame
*frame
);
276 // stuff used by MyGUIThread:
277 wxBitmap m_bmp
; // the bitmap drawn by MyGUIThread
278 wxCriticalSection m_csBmp
; // protects m_bmp
281 void OnGUIThreadEvent(wxThreadEvent
& event
);
282 void OnPaint(wxPaintEvent
&);
284 MyGUIThread m_thread
;
285 int m_nCurrentProgress
;
287 DECLARE_EVENT_TABLE()
290 // ============================================================================
292 // ============================================================================
294 // ----------------------------------------------------------------------------
295 // the application class
296 // ----------------------------------------------------------------------------
298 // Create a new application object
303 m_shuttingDown
= false;
306 // `Main program' equivalent, creating windows and returning main app frame
309 if ( !wxApp::OnInit() )
312 // uncomment this to get some debugging messages from the trace code
313 // on the console (or just set WXTRACE env variable to include "thread")
314 wxLog::AddTraceMask("thread");
316 // Create the main frame window
317 new MyFrame("wxWidgets threads sample");
322 // ----------------------------------------------------------------------------
324 // ----------------------------------------------------------------------------
326 BEGIN_EVENT_TABLE(MyFrame
, wxFrame
)
327 EVT_MENU(THREAD_QUIT
, MyFrame::OnQuit
)
328 EVT_MENU(THREAD_CLEAR
, MyFrame::OnClear
)
329 EVT_MENU(THREAD_START_THREAD
, MyFrame::OnStartThread
)
330 EVT_MENU(THREAD_START_THREADS
, MyFrame::OnStartThreads
)
331 EVT_MENU(THREAD_STOP_THREAD
, MyFrame::OnStopThread
)
332 EVT_MENU(THREAD_PAUSE_THREAD
, MyFrame::OnPauseThread
)
333 EVT_MENU(THREAD_RESUME_THREAD
, MyFrame::OnResumeThread
)
335 EVT_MENU(THREAD_START_WORKER
, MyFrame::OnStartWorker
)
336 EVT_MENU(THREAD_EXEC_MAIN
, MyFrame::OnExecMain
)
337 EVT_MENU(THREAD_START_GUI_THREAD
, MyFrame::OnStartGUIThread
)
339 EVT_MENU(THREAD_SHOWCPUS
, MyFrame::OnShowCPUs
)
340 EVT_MENU(THREAD_ABOUT
, MyFrame::OnAbout
)
342 EVT_UPDATE_UI(THREAD_START_WORKER
, MyFrame::OnUpdateWorker
)
343 EVT_THREAD(WORKER_EVENT
, MyFrame::OnWorkerEvent
)
344 EVT_IDLE(MyFrame::OnIdle
)
347 // My frame constructor
348 MyFrame::MyFrame(const wxString
& title
)
349 : wxFrame(NULL
, wxID_ANY
, title
)
351 m_oldLogger
= wxLog::GetActiveTarget();
353 SetIcon(wxICON(sample
));
356 wxMenuBar
*menuBar
= new wxMenuBar
;
358 wxMenu
*menuFile
= new wxMenu
;
359 menuFile
->Append(THREAD_CLEAR
, wxT("&Clear log\tCtrl-L"));
360 menuFile
->AppendSeparator();
361 menuFile
->Append(THREAD_QUIT
, wxT("E&xit\tAlt-X"));
362 menuBar
->Append(menuFile
, wxT("&File"));
364 wxMenu
*menuThread
= new wxMenu
;
365 menuThread
->Append(THREAD_START_THREAD
, wxT("&Start a new thread\tCtrl-N"));
366 menuThread
->Append(THREAD_START_THREADS
, wxT("Start &many threads at once"));
367 menuThread
->Append(THREAD_STOP_THREAD
, wxT("S&top the last spawned thread\tCtrl-S"));
368 menuThread
->AppendSeparator();
369 menuThread
->Append(THREAD_PAUSE_THREAD
, wxT("&Pause the last spawned running thread\tCtrl-P"));
370 menuThread
->Append(THREAD_RESUME_THREAD
, wxT("&Resume the first suspended thread\tCtrl-R"));
371 menuThread
->AppendSeparator();
372 menuThread
->Append(THREAD_START_WORKER
, wxT("Start a &worker thread\tCtrl-W"));
373 menuThread
->Append(THREAD_EXEC_MAIN
, wxT("&Launch a program from main thread\tF5"));
374 menuThread
->Append(THREAD_START_GUI_THREAD
, wxT("Launch a &GUI thread\tF6"));
375 menuBar
->Append(menuThread
, wxT("&Thread"));
377 wxMenu
*menuHelp
= new wxMenu
;
378 menuHelp
->Append(THREAD_SHOWCPUS
, wxT("&Show CPU count"));
379 menuHelp
->AppendSeparator();
380 menuHelp
->Append(THREAD_ABOUT
, wxT("&About"));
381 menuBar
->Append(menuHelp
, wxT("&Help"));
385 m_nRunning
= m_nCount
= 0;
387 m_dlgProgress
= NULL
;
391 #endif // wxUSE_STATUSBAR
393 // create the logging text control and a header showing the meaning of the
395 wxTextCtrl
*header
= new wxTextCtrl(this, wxID_ANY
, "",
396 wxDefaultPosition
, wxDefaultSize
,
398 DoLogLine(header
, " Time", " Thread", "Message");
399 m_txtctrl
= new wxTextCtrl(this, wxID_ANY
, "",
400 wxDefaultPosition
, wxDefaultSize
,
401 wxTE_MULTILINE
| wxTE_READONLY
);
402 wxLog::SetActiveTarget(this);
404 // use fixed width font to align output in nice columns
405 wxFont
font(wxNORMAL_FONT
->GetPointSize(), wxFONTFAMILY_TELETYPE
,
406 wxFONTSTYLE_NORMAL
, wxFONTWEIGHT_NORMAL
);
407 header
->SetFont(font
);
408 m_txtctrl
->SetFont(font
);
410 m_txtctrl
->SetFocus();
412 // layout and show the frame
413 wxBoxSizer
*sizer
= new wxBoxSizer(wxVERTICAL
);
414 sizer
->Add(header
, wxSizerFlags().Expand());
415 sizer
->Add(m_txtctrl
, wxSizerFlags(1).Expand());
424 wxLog::SetActiveTarget(m_oldLogger
);
426 // NB: although the OS will terminate all the threads anyhow when the main
427 // one exits, it's good practice to do it ourselves -- even if it's not
428 // completely trivial in this example
430 // tell all the threads to terminate: note that they can't terminate while
431 // we're deleting them because they will block in their OnExit() -- this is
432 // important as otherwise we might access invalid array elements
435 wxCriticalSectionLocker
locker(wxGetApp().m_critsect
);
437 // check if we have any threads running first
438 const wxArrayThread
& threads
= wxGetApp().m_threads
;
439 size_t count
= threads
.GetCount();
444 // set the flag indicating that all threads should exit
445 wxGetApp().m_shuttingDown
= true;
448 // now wait for them to really terminate
449 wxGetApp().m_semAllDone
.Wait();
453 MyFrame::DoLogLine(wxTextCtrl
*text
,
454 const wxString
& timestr
,
455 const wxString
& threadstr
,
458 text
->AppendText(wxString::Format("%9s %10s %s", timestr
, threadstr
, msg
));
462 MyFrame::DoLogRecord(wxLogLevel level
,
464 const wxLogRecordInfo
& info
)
466 // let the default GUI logger treat warnings and errors as they should be
467 // more noticeable than just another line in the log window and also trace
468 // messages as there may be too many of them
469 if ( level
<= wxLOG_Warning
|| level
== wxLOG_Trace
)
471 m_oldLogger
->LogRecord(level
, msg
, info
);
478 wxDateTime(info
.timestamp
).FormatISOTime(),
479 info
.threadId
== wxThread::GetMainId()
481 : wxString::Format("%lx", info
.threadId
),
486 MyThread
*MyFrame::CreateThread()
488 MyThread
*thread
= new MyThread
;
490 if ( thread
->Create() != wxTHREAD_NO_ERROR
)
492 wxLogError(wxT("Can't create thread!"));
495 wxCriticalSectionLocker
enter(wxGetApp().m_critsect
);
496 wxGetApp().m_threads
.Add(thread
);
501 void MyFrame::UpdateThreadStatus()
503 wxCriticalSectionLocker
enter(wxGetApp().m_critsect
);
505 // update the counts of running/total threads
507 nCount
= wxGetApp().m_threads
.Count();
508 for ( size_t n
= 0; n
< nCount
; n
++ )
510 if ( wxGetApp().m_threads
[n
]->IsRunning() )
514 if ( nCount
!= m_nCount
|| nRunning
!= m_nRunning
)
516 m_nRunning
= nRunning
;
519 wxLogStatus(this, wxT("%u threads total, %u running."), unsigned(nCount
), unsigned(nRunning
));
521 //else: avoid flicker - don't print anything
524 bool MyFrame::Cancelled()
526 wxCriticalSectionLocker
lock(m_csCancelled
);
531 // ----------------------------------------------------------------------------
532 // MyFrame - event handlers
533 // ----------------------------------------------------------------------------
535 void MyFrame::OnStartThreads(wxCommandEvent
& WXUNUSED(event
) )
539 s_num
= wxGetNumberFromUser(wxT("How many threads to start: "), wxT(""),
540 wxT("wxThread sample"), s_num
, 1, 10000, this);
548 unsigned count
= unsigned(s_num
), n
;
550 wxArrayThread threads
;
552 // first create them all...
553 for ( n
= 0; n
< count
; n
++ )
555 wxThread
*thr
= CreateThread();
557 // we want to show the effect of SetPriority(): the first thread will
558 // have the lowest priority, the second - the highest, all the rest
561 thr
->SetPriority(wxPRIORITY_MIN
);
563 thr
->SetPriority(wxPRIORITY_MAX
);
565 thr
->SetPriority(wxPRIORITY_DEFAULT
);
572 msg
.Printf(wxT("%d new threads created."), count
);
573 SetStatusText(msg
, 1);
574 #endif // wxUSE_STATUSBAR
576 // ...and then start them
577 for ( n
= 0; n
< count
; n
++ )
583 void MyFrame::OnStartThread(wxCommandEvent
& WXUNUSED(event
) )
585 MyThread
*thread
= CreateThread();
587 if ( thread
->Run() != wxTHREAD_NO_ERROR
)
589 wxLogError(wxT("Can't start thread!"));
593 SetStatusText(wxT("New thread started."), 1);
594 #endif // wxUSE_STATUSBAR
597 void MyFrame::OnStopThread(wxCommandEvent
& WXUNUSED(event
) )
599 wxThread
* toDelete
= NULL
;
601 wxCriticalSectionLocker
enter(wxGetApp().m_critsect
);
603 // stop the last thread
604 if ( wxGetApp().m_threads
.IsEmpty() )
606 wxLogError(wxT("No thread to stop!"));
610 toDelete
= wxGetApp().m_threads
.Last();
616 // This can still crash if the thread gets to delete itself
621 SetStatusText(wxT("Last thread stopped."), 1);
622 #endif // wxUSE_STATUSBAR
626 void MyFrame::OnResumeThread(wxCommandEvent
& WXUNUSED(event
) )
628 wxCriticalSectionLocker
enter(wxGetApp().m_critsect
);
630 // resume first suspended thread
631 size_t n
= 0, count
= wxGetApp().m_threads
.Count();
632 while ( n
< count
&& !wxGetApp().m_threads
[n
]->IsPaused() )
637 wxLogError(wxT("No thread to resume!"));
641 wxGetApp().m_threads
[n
]->Resume();
644 SetStatusText(wxT("Thread resumed."), 1);
645 #endif // wxUSE_STATUSBAR
649 void MyFrame::OnPauseThread(wxCommandEvent
& WXUNUSED(event
) )
651 wxCriticalSectionLocker
enter(wxGetApp().m_critsect
);
653 // pause last running thread
654 int n
= wxGetApp().m_threads
.Count() - 1;
655 while ( n
>= 0 && !wxGetApp().m_threads
[n
]->IsRunning() )
660 wxLogError(wxT("No thread to pause!"));
664 wxGetApp().m_threads
[n
]->Pause();
667 SetStatusText(wxT("Thread paused."), 1);
668 #endif // wxUSE_STATUSBAR
672 void MyFrame::OnIdle(wxIdleEvent
& event
)
674 UpdateThreadStatus();
679 void MyFrame::OnQuit(wxCommandEvent
& WXUNUSED(event
) )
684 void MyFrame::OnExecMain(wxCommandEvent
& WXUNUSED(event
))
686 wxString cmd
= wxGetTextFromUser("Please enter the command to execute",
691 "/bin/echo \"Message from another process\"",
695 return; // user clicked cancel
697 wxLogMessage(wxT("The exit code from the main program is %ld"),
701 void MyFrame::OnShowCPUs(wxCommandEvent
& WXUNUSED(event
))
705 int nCPUs
= wxThread::GetCPUCount();
709 msg
= wxT("Unknown number of CPUs");
713 msg
= wxT("WARNING: you're running without any CPUs!");
717 msg
= wxT("This system only has one CPU.");
721 msg
.Printf(wxT("This system has %d CPUs"), nCPUs
);
727 void MyFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
) )
729 wxMessageDialog
dialog(this,
730 wxT("wxWidgets multithreaded application sample\n")
731 wxT("(c) 1998 Julian Smart, Guilhem Lavaux\n")
732 wxT("(c) 2000 Robert Roebling\n")
733 wxT("(c) 1999,2009 Vadim Zeitlin"),
734 wxT("About wxThread sample"),
735 wxOK
| wxICON_INFORMATION
);
740 void MyFrame::OnClear(wxCommandEvent
& WXUNUSED(event
))
745 void MyFrame::OnUpdateWorker(wxUpdateUIEvent
& event
)
747 event
.Enable( m_dlgProgress
== NULL
);
750 void MyFrame::OnStartWorker(wxCommandEvent
& WXUNUSED(event
))
752 MyWorkerThread
*thread
= new MyWorkerThread(this);
754 if ( thread
->Create() != wxTHREAD_NO_ERROR
)
756 wxLogError(wxT("Can't create thread!"));
760 m_dlgProgress
= new wxProgressDialog
762 wxT("Progress dialog"),
763 wxT("Wait until the thread terminates or press [Cancel]"),
769 wxPD_ESTIMATED_TIME
|
773 // thread is not running yet, no need for crit sect
779 void MyFrame::OnWorkerEvent(wxThreadEvent
& event
)
781 int n
= event
.GetInt();
784 m_dlgProgress
->Destroy();
785 m_dlgProgress
= (wxProgressDialog
*)NULL
;
787 // the dialog is aborted because the event came from another thread, so
788 // we may need to wake up the main event loop for the dialog to be
794 if ( !m_dlgProgress
->Update(n
) )
796 wxCriticalSectionLocker
lock(m_csCancelled
);
803 void MyFrame::OnStartGUIThread(wxCommandEvent
& WXUNUSED(event
))
805 // we use this to check that disabling logging only affects the main thread
806 // but the messages from the worker thread will still be logged
808 wxLogMessage("You shouldn't see this message because of wxLogNull");
810 MyImageDialog
dlg(this);
816 // ----------------------------------------------------------------------------
818 // ----------------------------------------------------------------------------
820 BEGIN_EVENT_TABLE(MyImageDialog
, wxDialog
)
821 EVT_THREAD(GUITHREAD_EVENT
, MyImageDialog::OnGUIThreadEvent
)
822 EVT_PAINT(MyImageDialog::OnPaint
)
825 MyImageDialog::MyImageDialog(wxFrame
*parent
)
826 : wxDialog(parent
, wxID_ANY
, "Image created by a secondary thread",
827 wxDefaultPosition
, wxSize(GUITHREAD_BMP_SIZE
,GUITHREAD_BMP_SIZE
)*1.5, wxDEFAULT_DIALOG_STYLE
),
830 m_nCurrentProgress
= 0;
834 // NOTE: no need to lock m_csBmp until the thread isn't started:
837 if (!m_bmp
.Create(GUITHREAD_BMP_SIZE
,GUITHREAD_BMP_SIZE
) || !m_bmp
.IsOk())
839 wxLogError("Couldn't create the bitmap!");
844 wxMemoryDC
dc(m_bmp
);
845 dc
.SetBackground(*wxBLACK_BRUSH
);
848 // draw the bitmap from a secondary thread
849 if ( m_thread
.Create() != wxTHREAD_NO_ERROR
||
850 m_thread
.Run() != wxTHREAD_NO_ERROR
)
852 wxLogError(wxT("Can't create/run thread!"));
857 MyImageDialog::~MyImageDialog()
859 // in case our thread is still running and for some reason we are destroyed,
860 // do wait for the thread to complete as it assumes that its MyImageDialog
861 // pointer is always valid
865 void MyImageDialog::OnGUIThreadEvent(wxThreadEvent
& event
)
867 m_nCurrentProgress
= int(((float)event
.GetInt()*100)/GUITHREAD_NUM_UPDATES
);
872 void MyImageDialog::OnPaint(wxPaintEvent
& WXUNUSED(evt
))
876 const wxSize
& sz
= dc
.GetSize();
880 wxCriticalSectionLocker
locker(m_csBmp
);
881 dc
.DrawBitmap(m_bmp
, (sz
.GetWidth()-GUITHREAD_BMP_SIZE
)/2,
882 (sz
.GetHeight()-GUITHREAD_BMP_SIZE
)/2);
885 // paint a sort of progress bar with a 10px border:
886 dc
.SetBrush(*wxRED_BRUSH
);
887 dc
.DrawRectangle(10,10, m_nCurrentProgress
*(sz
.GetWidth()-20)/100,30);
888 dc
.SetTextForeground(*wxBLUE
);
889 dc
.DrawText(wxString::Format("%d%%", m_nCurrentProgress
),
890 (sz
.GetWidth()-dc
.GetCharWidth()*2)/2,
891 25-dc
.GetCharHeight()/2);
894 // ----------------------------------------------------------------------------
896 // ----------------------------------------------------------------------------
904 MyThread::~MyThread()
906 wxCriticalSectionLocker
locker(wxGetApp().m_critsect
);
908 wxArrayThread
& threads
= wxGetApp().m_threads
;
909 threads
.Remove(this);
911 if ( threads
.IsEmpty() )
913 // signal the main thread that there are no more threads left if it is
915 if ( wxGetApp().m_shuttingDown
)
917 wxGetApp().m_shuttingDown
= false;
919 wxGetApp().m_semAllDone
.Post();
924 wxThread::ExitCode
MyThread::Entry()
926 wxLogMessage("Thread started (priority = %u).", GetPriority());
928 for ( m_count
= 0; m_count
< 10; m_count
++ )
930 // check if the application is shutting down: in this case all threads
931 // should stop a.s.a.p.
933 wxCriticalSectionLocker
locker(wxGetApp().m_critsect
);
934 if ( wxGetApp().m_shuttingDown
)
938 // check if just this thread was asked to exit
942 wxLogMessage("Thread progress: %u", m_count
);
944 // wxSleep() can't be called from non-GUI thread!
945 wxThread::Sleep(1000);
948 wxLogMessage("Thread finished.");
954 // ----------------------------------------------------------------------------
956 // ----------------------------------------------------------------------------
958 // define this symbol to 1 to test if the YieldFor() call in the wxProgressDialog::Update
959 // function provokes a race condition in which the second wxThreadEvent posted by
960 // MyWorkerThread::Entry is processed by the YieldFor() call of wxProgressDialog::Update
961 // and results in the destruction of the progress dialog itself, resulting in a crash later.
962 #define TEST_YIELD_RACE_CONDITION 0
964 MyWorkerThread::MyWorkerThread(MyFrame
*frame
)
971 void MyWorkerThread::OnExit()
975 wxThread::ExitCode
MyWorkerThread::Entry()
977 #if TEST_YIELD_RACE_CONDITION
981 wxThreadEvent
event( wxEVT_THREAD
, WORKER_EVENT
);
984 wxQueueEvent( m_frame
, event
.Clone() );
987 wxQueueEvent( m_frame
, event
.Clone() );
989 for ( m_count
= 0; !m_frame
->Cancelled() && (m_count
< 100); m_count
++ )
991 // check if we were asked to exit
995 // create any type of command event here
996 wxThreadEvent
event( wxEVT_THREAD
, WORKER_EVENT
);
997 event
.SetInt( m_count
);
999 // send in a thread-safe way
1000 wxQueueEvent( m_frame
, event
.Clone() );
1005 wxThreadEvent
event( wxEVT_THREAD
, WORKER_EVENT
);
1006 event
.SetInt(-1); // that's all
1007 wxQueueEvent( m_frame
, event
.Clone() );
1014 // ----------------------------------------------------------------------------
1016 // ----------------------------------------------------------------------------
1018 wxThread::ExitCode
MyGUIThread::Entry()
1020 // uncomment this to check that disabling logging here does disable it for
1021 // this thread -- but not the main one if you also comment out wxLogNull
1022 // line in MyFrame::OnStartGUIThread()
1025 // this goes to the main window
1026 wxLogMessage("GUI thread starting");
1028 // use a thread-specific log target for this thread to show that its
1029 // messages don't appear in the main window while it runs
1031 wxLog::SetThreadActiveTarget(&logBuf
);
1033 for (int i
=0; i
<GUITHREAD_NUM_UPDATES
&& !TestDestroy(); i
++)
1035 // inform the GUI toolkit that we're going to use GUI functions
1036 // from a secondary thread:
1040 wxCriticalSectionLocker
lock(m_dlg
->m_csBmp
);
1042 // draw some more stuff on the bitmap
1043 wxMemoryDC
dc(m_dlg
->m_bmp
);
1044 dc
.SetBrush((i%2
)==0 ? *wxBLUE_BRUSH
: *wxGREEN_BRUSH
);
1045 dc
.DrawRectangle(rand()%GUITHREAD_BMP_SIZE
, rand()%GUITHREAD_BMP_SIZE
, 30, 30);
1047 // simulate long drawing time:
1051 // if we don't release the GUI mutex the MyImageDialog won't be able to refresh
1054 // notify the dialog that another piece of our masterpiece is complete:
1055 wxThreadEvent
event( wxEVT_THREAD
, GUITHREAD_EVENT
);
1057 wxQueueEvent( m_dlg
, event
.Clone() );
1059 if ( !((i
+ 1) % 10) )
1061 // this message will go to the buffer
1062 wxLogMessage("Step #%d.", i
+ 1);
1065 // give the main thread the time to refresh before we lock the GUI mutex again
1066 // FIXME: find a better way to do this!
1070 // now remove the thread-specific thread target
1071 wxLog::SetThreadActiveTarget(NULL
);
1073 // so that this goes to the main window again
1074 wxLogMessage("GUI thread finished.");