]> git.saurik.com Git - wxWidgets.git/blame - samples/thread/thread.cpp
Applied [ 587500 ] Update CW project file for wxMSW
[wxWidgets.git] / samples / thread / thread.cpp
CommitLineData
82052aff 1/////////////////////////////////////////////////////////////////////////////
c4f02b1f 2// Name: thread.cpp
82052aff 3// Purpose: wxWindows thread sample
ffc45b67 4// Author: Guilhem Lavaux, Vadim Zeitlin
82052aff
GL
5// Modified by:
6// Created: 06/16/98
7// RCS-ID: $Id$
ffc45b67 8// Copyright: (c) 1998-2002 wxWindows team
3222fde2 9// Licence: wxWindows license
82052aff
GL
10/////////////////////////////////////////////////////////////////////////////
11
82052aff
GL
12// For compilers that support precompilation, includes "wx/wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
3222fde2 16 #pragma hdrstop
82052aff
GL
17#endif
18
19#ifndef WX_PRECOMP
3222fde2 20 #include "wx/wx.h"
82052aff
GL
21#endif
22
3222fde2
VZ
23#if !wxUSE_THREADS
24 #error "This sample requires thread support!"
25#endif // wxUSE_THREADS
26
82052aff
GL
27#include "wx/thread.h"
28#include "wx/dynarray.h"
3222fde2 29#include "wx/time.h"
82052aff 30
b9de1315
VZ
31#include "wx/progdlg.h"
32
ffc45b67 33// define this to use wxExecute in the exec tests, otherwise just use system
cd5e9298 34#define USE_EXECUTE
ffc45b67 35
a4b59324
VZ
36#ifdef USE_EXECUTE
37 #define EXEC(cmd) wxExecute((cmd), wxEXEC_SYNC)
38#else
39 #define EXEC(cmd) system(cmd)
40#endif
b8b9762a 41
1bd3e1ef
GL
42class MyThread;
43WX_DEFINE_ARRAY(wxThread *, wxArrayThread);
44
82052aff 45// Define a new application type
bf1852e1 46class MyApp : public wxApp
82052aff 47{
98f026a6 48public:
ffc45b67
VZ
49 MyApp();
50 virtual ~MyApp();
51
98f026a6
VZ
52 virtual bool OnInit();
53
54public:
55 // all the threads currently alive - as soon as the thread terminates, it's
56 // removed from the array
57 wxArrayThread m_threads;
58
59 // crit section protects access to all of the arrays below
60 wxCriticalSection m_critsect;
ffc45b67
VZ
61
62 // the (mutex, condition) pair used to wait for the threads to exit, see
63 // MyFrame::OnQuit()
64 wxMutex m_mutexAllDone;
65 wxCondition m_condAllDone;
66
67 // the last exiting thread should signal m_condAllDone if this is true
68 // (protected by the same m_critsect)
69 bool m_waitingUntilAllDone;
82052aff
GL
70};
71
1bd3e1ef 72// Create a new application object
98f026a6 73IMPLEMENT_APP(MyApp)
82052aff
GL
74
75// Define a new frame type
76class MyFrame: public wxFrame
77{
a6b0bd49
VZ
78public:
79 // ctor
bf1852e1 80 MyFrame(wxFrame *frame, const wxString& title, int x, int y, int w, int h);
3222fde2 81
a6b0bd49
VZ
82 // operations
83 void WriteText(const wxString& text) { m_txtctrl->WriteText(text); }
84
b9de1315
VZ
85 // accessors for MyWorkerThread (called in its context!)
86 bool Cancelled();
87
ffc45b67 88protected:
a6b0bd49 89 // callbacks
82052aff 90 void OnQuit(wxCommandEvent& event);
bee503b0 91 void OnClear(wxCommandEvent& event);
a6b0bd49 92
82052aff 93 void OnStartThread(wxCommandEvent& event);
7c3d7e2d 94 void OnStartThreads(wxCommandEvent& event);
82052aff
GL
95 void OnStopThread(wxCommandEvent& event);
96 void OnPauseThread(wxCommandEvent& event);
a6b0bd49 97 void OnResumeThread(wxCommandEvent& event);
b9de1315 98
ce6d2511
RR
99 void OnStartWorker(wxCommandEvent& event);
100 void OnWorkerEvent(wxCommandEvent& event);
b9de1315 101 void OnUpdateWorker(wxUpdateUIEvent& event);
a6b0bd49 102
a4b59324
VZ
103 void OnExecMain(wxCommandEvent& event);
104 void OnExecThread(wxCommandEvent& event);
105
106 void OnShowCPUs(wxCommandEvent& event);
107 void OnAbout(wxCommandEvent& event);
108
3222fde2 109 void OnIdle(wxIdleEvent &event);
3222fde2 110
a6b0bd49 111private:
7c3d7e2d
VZ
112 // helper function - creates a new thread (but doesn't run it)
113 MyThread *CreateThread();
88ac883a 114
bf1852e1
VZ
115 // just some place to put our messages in
116 wxTextCtrl *m_txtctrl;
3222fde2 117
7c3d7e2d
VZ
118 // remember the number of running threads and total number of threads
119 size_t m_nRunning, m_nCount;
120
b9de1315
VZ
121 // the progress dialog which we show while worker thread is running
122 wxProgressDialog *m_dlgProgress;
123
124 // was the worker thread cancelled by user?
125 bool m_cancelled;
126
127 // protects m_cancelled
128 wxCriticalSection m_critsectWork;
129
a6b0bd49 130 DECLARE_EVENT_TABLE()
82052aff
GL
131};
132
ce6d2511
RR
133// ID for the menu commands
134enum
135{
a4b59324
VZ
136 THREAD_QUIT = 1,
137 THREAD_TEXT = 101,
138 THREAD_CLEAR,
139 THREAD_START_THREAD = 201,
140 THREAD_START_THREADS,
141 THREAD_STOP_THREAD,
142 THREAD_PAUSE_THREAD,
143 THREAD_RESUME_THREAD,
144 THREAD_START_WORKER,
145
146 THREAD_EXEC_MAIN,
147 THREAD_EXEC_THREAD,
148
149 THREAD_SHOWCPUS,
150 THREAD_ABOUT,
151
ce6d2511
RR
152 WORKER_EVENT // this one gets sent from the worker thread
153};
154
a4b59324 155// ----------------------------------------------------------------------------
ce6d2511 156// GUI thread
a4b59324 157// ----------------------------------------------------------------------------
ce6d2511 158
bee503b0 159class MyThread : public wxThread
82052aff 160{
a6b0bd49 161public:
82052aff 162 MyThread(MyFrame *frame);
3222fde2
VZ
163
164 // thread execution starts here
165 virtual void *Entry();
166
bf1852e1
VZ
167 // called when the thread exits - whether it terminates normally or is
168 // stopped with Delete() (but not when it is Kill()ed!)
bee503b0
VZ
169 virtual void OnExit();
170
3222fde2
VZ
171 // write something to the text control
172 void WriteText(const wxString& text);
a6b0bd49
VZ
173
174public:
175 size_t m_count;
82052aff
GL
176 MyFrame *m_frame;
177};
178
179MyThread::MyThread(MyFrame *frame)
a6b0bd49 180 : wxThread()
82052aff 181{
a6b0bd49
VZ
182 m_count = 0;
183 m_frame = frame;
82052aff
GL
184}
185
3222fde2
VZ
186void MyThread::WriteText(const wxString& text)
187{
188 wxString msg;
3222fde2
VZ
189
190 // before doing any GUI calls we must ensure that this thread is the only
191 // one doing it!
88ac883a 192
7b90a8f2 193 wxMutexGuiEnter();
88ac883a 194
20e05ffb 195 msg << text;
3222fde2 196 m_frame->WriteText(msg);
b9de1315 197
7b90a8f2 198 wxMutexGuiLeave();
bee503b0
VZ
199}
200
201void MyThread::OnExit()
202{
1bd3e1ef
GL
203 wxCriticalSectionLocker locker(wxGetApp().m_critsect);
204
ffc45b67
VZ
205 wxArrayThread& threads = wxGetApp().m_threads;
206 threads.Remove(this);
207
208 if ( threads.IsEmpty() )
209 {
210 // signal the main thread that there are no more threads left if it is
211 // waiting for us
212 if ( wxGetApp().m_waitingUntilAllDone )
213 {
214 wxGetApp().m_waitingUntilAllDone = FALSE;
215
216 wxMutexLocker lock(wxGetApp().m_mutexAllDone);
217 wxGetApp().m_condAllDone.Signal();
218 }
219 }
3222fde2
VZ
220}
221
82052aff
GL
222void *MyThread::Entry()
223{
a6b0bd49 224 wxString text;
3222fde2 225
aec18ff7 226 text.Printf(wxT("Thread 0x%x started (priority = %u).\n"),
b568d04f 227 GetId(), GetPriority());
3222fde2 228 WriteText(text);
2286341c 229 // wxLogMessage(text); -- test wxLog thread safeness
3222fde2 230
bee503b0 231 for ( m_count = 0; m_count < 10; m_count++ )
3222fde2
VZ
232 {
233 // check if we were asked to exit
234 if ( TestDestroy() )
235 break;
236
4693b20c 237 text.Printf(wxT("[%u] Thread 0x%x here.\n"), m_count, GetId());
3222fde2 238 WriteText(text);
a6b0bd49 239
bf1852e1
VZ
240 // wxSleep() can't be called from non-GUI thread!
241 wxThread::Sleep(1000);
a6b0bd49 242 }
3222fde2 243
4693b20c 244 text.Printf(wxT("Thread 0x%x finished.\n"), GetId());
3222fde2 245 WriteText(text);
2286341c 246 // wxLogMessage(text); -- test wxLog thread safeness
3222fde2 247
a6b0bd49 248 return NULL;
82052aff
GL
249}
250
a4b59324 251// ----------------------------------------------------------------------------
ce6d2511 252// worker thread
a4b59324 253// ----------------------------------------------------------------------------
ce6d2511
RR
254
255class MyWorkerThread : public wxThread
3222fde2 256{
ce6d2511
RR
257public:
258 MyWorkerThread(MyFrame *frame);
259
260 // thread execution starts here
261 virtual void *Entry();
262
263 // called when the thread exits - whether it terminates normally or is
264 // stopped with Delete() (but not when it is Kill()ed!)
265 virtual void OnExit();
266
267public:
268 MyFrame *m_frame;
269 size_t m_count;
3222fde2 270};
82052aff 271
ce6d2511
RR
272MyWorkerThread::MyWorkerThread(MyFrame *frame)
273 : wxThread()
274{
275 m_frame = frame;
276 m_count = 0;
277}
278
279void MyWorkerThread::OnExit()
280{
281}
282
283void *MyWorkerThread::Entry()
284{
b9de1315 285 for ( m_count = 0; !m_frame->Cancelled() && (m_count < 100); m_count++ )
ce6d2511
RR
286 {
287 // check if we were asked to exit
288 if ( TestDestroy() )
289 break;
b9de1315 290
b9de1315 291 // create any type of command event here
ce6d2511 292 wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, WORKER_EVENT );
b9de1315 293 event.SetInt( m_count );
b9de1315 294
07f5b19a 295 // send in a thread-safe way
ce6d2511 296 wxPostEvent( m_frame, event );
b9de1315 297
07f5b19a 298 // wxSleep() can't be called from non-main thread!
b9de1315 299 wxThread::Sleep(200);
ce6d2511
RR
300 }
301
b9de1315
VZ
302 wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, WORKER_EVENT );
303 event.SetInt(-1); // that's all
304 wxPostEvent( m_frame, event );
305
ce6d2511
RR
306 return NULL;
307}
308
a4b59324
VZ
309// ----------------------------------------------------------------------------
310// a thread which simply calls wxExecute
311// ----------------------------------------------------------------------------
312
313class MyExecThread : public wxThread
314{
315public:
316 MyExecThread(const wxChar *command) : wxThread(wxTHREAD_JOINABLE),
317 m_command(command)
318 {
319 Create();
320 }
321
322 virtual ExitCode Entry()
323 {
324 return (ExitCode)EXEC(m_command);
325 }
326
327private:
328 wxString m_command;
329};
330
331// ----------------------------------------------------------------------------
332// implementation
333// ----------------------------------------------------------------------------
ce6d2511 334
82052aff 335BEGIN_EVENT_TABLE(MyFrame, wxFrame)
a4b59324
VZ
336 EVT_MENU(THREAD_QUIT, MyFrame::OnQuit)
337 EVT_MENU(THREAD_CLEAR, MyFrame::OnClear)
338 EVT_MENU(THREAD_START_THREAD, MyFrame::OnStartThread)
339 EVT_MENU(THREAD_START_THREADS, MyFrame::OnStartThreads)
340 EVT_MENU(THREAD_STOP_THREAD, MyFrame::OnStopThread)
341 EVT_MENU(THREAD_PAUSE_THREAD, MyFrame::OnPauseThread)
342 EVT_MENU(THREAD_RESUME_THREAD, MyFrame::OnResumeThread)
343
344 EVT_MENU(THREAD_EXEC_MAIN, MyFrame::OnExecMain)
345 EVT_MENU(THREAD_EXEC_THREAD, MyFrame::OnExecThread)
346
347 EVT_MENU(THREAD_SHOWCPUS, MyFrame::OnShowCPUs)
348 EVT_MENU(THREAD_ABOUT, MyFrame::OnAbout)
349
350 EVT_UPDATE_UI(THREAD_START_WORKER, MyFrame::OnUpdateWorker)
351 EVT_MENU(THREAD_START_WORKER, MyFrame::OnStartWorker)
ce6d2511 352 EVT_MENU(WORKER_EVENT, MyFrame::OnWorkerEvent)
a6b0bd49 353
3222fde2 354 EVT_IDLE(MyFrame::OnIdle)
82052aff
GL
355END_EVENT_TABLE()
356
ffc45b67
VZ
357MyApp::MyApp()
358 : m_condAllDone(m_mutexAllDone)
359{
360 // the mutex associated with a condition must be initially locked, it will
361 // only be unlocked when we call Wait()
362 m_mutexAllDone.Lock();
363
364 m_waitingUntilAllDone = FALSE;
365}
366
367MyApp::~MyApp()
368{
369 // the mutex must be unlocked before being destroyed
370 m_mutexAllDone.Unlock();
371}
372
82052aff 373// `Main program' equivalent, creating windows and returning main app frame
3222fde2 374bool MyApp::OnInit()
82052aff 375{
a4b59324
VZ
376 // uncomment this to get some debugging messages from the trace code
377 // on the console (or just set WXTRACE env variable to include "thread")
378 //wxLog::AddTraceMask("thread");
b8b9762a 379
a6b0bd49 380 // Create the main frame window
bee503b0
VZ
381 MyFrame *frame = new MyFrame((wxFrame *)NULL, "wxWindows threads sample",
382 50, 50, 450, 340);
3222fde2 383
a6b0bd49 384 // Make a menubar
a4b59324
VZ
385 wxMenuBar *menuBar = new wxMenuBar;
386
387 wxMenu *menuFile = new wxMenu;
388 menuFile->Append(THREAD_CLEAR, "&Clear log\tCtrl-L");
389 menuFile->AppendSeparator();
390 menuFile->Append(THREAD_QUIT, "E&xit\tAlt-X");
391 menuBar->Append(menuFile, "&File");
392
393 wxMenu *menuThread = new wxMenu;
394 menuThread->Append(THREAD_START_THREAD, "&Start a new thread\tCtrl-N");
395 menuThread->Append(THREAD_START_THREADS, "Start &many threads at once");
396 menuThread->Append(THREAD_STOP_THREAD, "S&top a running thread\tCtrl-S");
397 menuThread->AppendSeparator();
398 menuThread->Append(THREAD_PAUSE_THREAD, "&Pause a running thread\tCtrl-P");
399 menuThread->Append(THREAD_RESUME_THREAD, "&Resume suspended thread\tCtrl-R");
400 menuThread->AppendSeparator();
401 menuThread->Append(THREAD_START_WORKER, "Start &worker thread\tCtrl-W");
402 menuBar->Append(menuThread, "&Thread");
403
404 wxMenu *menuExec = new wxMenu;
405 menuExec->Append(THREAD_EXEC_MAIN, "&Launch a program from main thread\tF5");
406 menuExec->Append(THREAD_EXEC_THREAD, "L&aunch a program from a thread\tCtrl-F5");
407 menuBar->Append(menuExec, "&Execute");
408
409 wxMenu *menuHelp = new wxMenu;
410 menuHelp->Append(THREAD_SHOWCPUS, "&Show CPU count");
411 menuHelp->AppendSeparator();
412 menuHelp->Append(THREAD_ABOUT, "&About...");
413 menuBar->Append(menuHelp, "&Help");
414
415 frame->SetMenuBar(menuBar);
3222fde2 416
a6b0bd49
VZ
417 // Show the frame
418 frame->Show(TRUE);
3222fde2 419
a6b0bd49 420 SetTopWindow(frame);
3222fde2 421
a6b0bd49 422 return TRUE;
82052aff
GL
423}
424
425// My frame constructor
bf1852e1
VZ
426MyFrame::MyFrame(wxFrame *frame, const wxString& title,
427 int x, int y, int w, int h)
a6b0bd49 428 : wxFrame(frame, -1, title, wxPoint(x, y), wxSize(w, h))
82052aff 429{
7c3d7e2d
VZ
430 m_nRunning = m_nCount = 0;
431
b9de1315
VZ
432 m_dlgProgress = (wxProgressDialog *)NULL;
433
7c3d7e2d 434 CreateStatusBar(2);
3222fde2 435
bee503b0
VZ
436 m_txtctrl = new wxTextCtrl(this, -1, "", wxPoint(0, 0), wxSize(0, 0),
437 wxTE_MULTILINE | wxTE_READONLY);
82052aff 438
a6b0bd49 439}
82052aff 440
7c3d7e2d 441MyThread *MyFrame::CreateThread()
a6b0bd49
VZ
442{
443 MyThread *thread = new MyThread(this);
3222fde2 444
bf1852e1
VZ
445 if ( thread->Create() != wxTHREAD_NO_ERROR )
446 {
4693b20c 447 wxLogError(wxT("Can't create thread!"));
bf1852e1 448 }
3222fde2 449
1bd3e1ef
GL
450 wxCriticalSectionLocker enter(wxGetApp().m_critsect);
451 wxGetApp().m_threads.Add(thread);
bf1852e1 452
7c3d7e2d
VZ
453 return thread;
454}
455
456void MyFrame::OnStartThreads(wxCommandEvent& WXUNUSED(event) )
457{
b568d04f
VZ
458 static long s_num = 10;
459
460 s_num = wxGetNumberFromUser("How many threads to start: ", "",
461 "wxThread sample", s_num, 1, 10000, this);
462 if ( s_num == -1 )
463 {
464 s_num = 10;
7c3d7e2d 465
7c3d7e2d 466 return;
b568d04f
VZ
467 }
468
469 size_t count = (size_t)s_num, n;
7c3d7e2d
VZ
470
471 wxArrayThread threads;
472
473 // first create them all...
474 for ( n = 0; n < count; n++ )
475 {
98f026a6
VZ
476 wxThread *thr = CreateThread();
477
478 // we want to show the effect of SetPriority(): the first thread will
479 // have the lowest priority, the second - the highest, all the rest
480 // the normal one
481 if ( n == 0 )
482 thr->SetPriority(WXTHREAD_MIN_PRIORITY);
483 else if ( n == 1 )
484 thr->SetPriority(WXTHREAD_MAX_PRIORITY);
485 else
486 thr->SetPriority(WXTHREAD_DEFAULT_PRIORITY);
487
488 threads.Add(thr);
7c3d7e2d
VZ
489 }
490
491 wxString msg;
4693b20c 492 msg.Printf(wxT("%d new threads created."), count);
7c3d7e2d
VZ
493 SetStatusText(msg, 1);
494
495 // ...and then start them
496 for ( n = 0; n < count; n++ )
497 {
498 threads[n]->Run();
499 }
500}
501
502void MyFrame::OnStartThread(wxCommandEvent& WXUNUSED(event) )
503{
504 MyThread *thread = CreateThread();
505
bf1852e1
VZ
506 if ( thread->Run() != wxTHREAD_NO_ERROR )
507 {
4693b20c 508 wxLogError(wxT("Can't start thread!"));
bf1852e1 509 }
7c3d7e2d
VZ
510
511 SetStatusText("New thread started.", 1);
82052aff
GL
512}
513
e3e65dac 514void MyFrame::OnStopThread(wxCommandEvent& WXUNUSED(event) )
82052aff 515{
b8b9762a
VZ
516 wxGetApp().m_critsect.Enter();
517
bf1852e1 518 // stop the last thread
1bd3e1ef 519 if ( wxGetApp().m_threads.IsEmpty() )
bee503b0 520 {
4693b20c 521 wxLogError(wxT("No thread to stop!"));
b8b9762a
VZ
522
523 wxGetApp().m_critsect.Leave();
bee503b0 524 }
bf1852e1
VZ
525 else
526 {
1bd3e1ef 527 wxThread *thread = wxGetApp().m_threads.Last();
7c3d7e2d
VZ
528
529 // it's important to leave critical section before calling Delete()
1bd3e1ef 530 // because delete will (implicitly) call OnExit() which also tries
7c3d7e2d 531 // to enter the same crit section - would dead lock.
1bd3e1ef 532 wxGetApp().m_critsect.Leave();
7c3d7e2d
VZ
533
534 thread->Delete();
535
536 SetStatusText("Thread stopped.", 1);
bf1852e1 537 }
a6b0bd49 538}
82052aff 539
a6b0bd49
VZ
540void MyFrame::OnResumeThread(wxCommandEvent& WXUNUSED(event) )
541{
1bd3e1ef 542 wxCriticalSectionLocker enter(wxGetApp().m_critsect);
bee503b0 543
3222fde2 544 // resume first suspended thread
1bd3e1ef
GL
545 size_t n = 0, count = wxGetApp().m_threads.Count();
546 while ( n < count && !wxGetApp().m_threads[n]->IsPaused() )
bf1852e1 547 n++;
3222fde2 548
bf1852e1 549 if ( n == count )
7c3d7e2d 550 {
4693b20c 551 wxLogError(wxT("No thread to resume!"));
7c3d7e2d 552 }
a6b0bd49 553 else
7c3d7e2d 554 {
1bd3e1ef 555 wxGetApp().m_threads[n]->Resume();
7c3d7e2d
VZ
556
557 SetStatusText("Thread resumed.", 1);
558 }
82052aff
GL
559}
560
e3e65dac 561void MyFrame::OnPauseThread(wxCommandEvent& WXUNUSED(event) )
f3855ef0 562{
1bd3e1ef 563 wxCriticalSectionLocker enter(wxGetApp().m_critsect);
bee503b0 564
3222fde2 565 // pause last running thread
1bd3e1ef
GL
566 int n = wxGetApp().m_threads.Count() - 1;
567 while ( n >= 0 && !wxGetApp().m_threads[n]->IsRunning() )
a6b0bd49 568 n--;
3222fde2 569
a6b0bd49 570 if ( n < 0 )
7c3d7e2d 571 {
4693b20c 572 wxLogError(wxT("No thread to pause!"));
7c3d7e2d 573 }
a6b0bd49 574 else
7c3d7e2d 575 {
1bd3e1ef 576 wxGetApp().m_threads[n]->Pause();
88ac883a 577
7c3d7e2d
VZ
578 SetStatusText("Thread paused.", 1);
579 }
f3855ef0
RR
580}
581
3222fde2
VZ
582// set the frame title indicating the current number of threads
583void MyFrame::OnIdle(wxIdleEvent &event)
584{
ffc45b67
VZ
585 wxCriticalSectionLocker enter(wxGetApp().m_critsect);
586
7fe4f500 587 // update the counts of running/total threads
3222fde2 588 size_t nRunning = 0,
1bd3e1ef 589 nCount = wxGetApp().m_threads.Count();
3222fde2
VZ
590 for ( size_t n = 0; n < nCount; n++ )
591 {
1bd3e1ef 592 if ( wxGetApp().m_threads[n]->IsRunning() )
3222fde2
VZ
593 nRunning++;
594 }
595
7c3d7e2d
VZ
596 if ( nCount != m_nCount || nRunning != m_nRunning )
597 {
598 m_nRunning = nRunning;
599 m_nCount = nCount;
600
4693b20c 601 wxLogStatus(this, wxT("%u threads total, %u running."), nCount, nRunning);
7c3d7e2d
VZ
602 }
603 //else: avoid flicker - don't print anything
f3855ef0 604}
82052aff 605
e3e65dac 606void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event) )
82052aff 607{
ffc45b67
VZ
608 // NB: although the OS will terminate all the threads anyhow when the main
609 // one exits, it's good practice to do it ourselves -- even if it's not
610 // completely trivial in this example
611
612 // tell all the threads to terminate: note that they can't terminate while
613 // we're deleting them because they will block in their OnExit() -- this is
614 // important as otherwise we might access invalid array elements
bf1852e1 615 {
ffc45b67
VZ
616 wxGetApp().m_critsect.Enter();
617
618 // check if we have any threads running first
619 const wxArrayThread& threads = wxGetApp().m_threads;
620 size_t count = threads.GetCount();
621
622 if ( count )
623 {
624 // we do, ask them to stop
625 for ( size_t n = 0; n < count; n++ )
626 {
627 threads[n]->Delete();
628 }
629
630 // set the flag for MyThread::OnExit()
631 wxGetApp().m_waitingUntilAllDone = TRUE;
632 }
633
634 wxGetApp().m_critsect.Leave();
635
636 if ( count )
637 {
638 // now wait for them to really terminate but leave the GUI mutex
639 // before doing it as otherwise we might dead lock
640 wxMutexGuiLeave();
641
642 wxGetApp().m_condAllDone.Wait();
643
644 wxMutexGuiEnter();
645 }
646 //else: no threads to terminate, no condition to wait for
bf1852e1 647 }
3222fde2 648
a6b0bd49 649 Close(TRUE);
82052aff
GL
650}
651
a4b59324
VZ
652void MyFrame::OnExecMain(wxCommandEvent& WXUNUSED(event))
653{
4fce73fc 654 wxLogMessage(wxT("The exit code from the main program is %ld"),
a4b59324
VZ
655 EXEC("/bin/echo \"main program\""));
656}
657
658void MyFrame::OnExecThread(wxCommandEvent& WXUNUSED(event))
659{
4fce73fc 660 MyExecThread thread(wxT("/bin/echo \"child thread\""));
a4b59324
VZ
661 thread.Run();
662
4fce73fc 663 wxLogMessage(wxT("The exit code from a child thread is %ld"),
a4b59324
VZ
664 (long)thread.Wait());
665}
666
667void MyFrame::OnShowCPUs(wxCommandEvent& WXUNUSED(event))
668{
669 wxString msg;
670
671 int nCPUs = wxThread::GetCPUCount();
672 switch ( nCPUs )
673 {
674 case -1:
675 msg = "Unknown number of CPUs";
676 break;
677
678 case 0:
679 msg = "WARNING: you're running without any CPUs!";
680 break;
681
682 case 1:
683 msg = "This system only has one CPU.";
684 break;
685
686 default:
4fce73fc 687 msg.Printf(wxT("This system has %d CPUs"), nCPUs);
a4b59324
VZ
688 }
689
690 wxLogMessage(msg);
691}
692
e3e65dac 693void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event) )
82052aff 694{
bf1852e1
VZ
695 wxMessageDialog dialog(this, "wxWindows multithreaded application sample\n"
696 "(c) 1998 Julian Smart, Guilhem Lavaux\n"
07f5b19a
RR
697 "(c) 1999 Vadim Zeitlin\n"
698 "(c) 2000 Robert Roebling",
3222fde2
VZ
699 "About wxThread sample",
700 wxOK | wxICON_INFORMATION);
701
a6b0bd49 702 dialog.ShowModal();
82052aff
GL
703}
704
bee503b0
VZ
705void MyFrame::OnClear(wxCommandEvent& WXUNUSED(event))
706{
707 m_txtctrl->Clear();
708}
ce6d2511 709
b9de1315
VZ
710void MyFrame::OnUpdateWorker(wxUpdateUIEvent& event)
711{
712 event.Enable( m_dlgProgress == NULL );
713}
714
ce6d2511
RR
715void MyFrame::OnStartWorker(wxCommandEvent& WXUNUSED(event))
716{
717 MyWorkerThread *thread = new MyWorkerThread(this);
718
719 if ( thread->Create() != wxTHREAD_NO_ERROR )
720 {
4693b20c 721 wxLogError(wxT("Can't create thread!"));
ce6d2511 722 }
b9de1315
VZ
723
724 m_dlgProgress = new wxProgressDialog
725 (
726 "Progress dialog",
727 "Wait until the thread terminates or press [Cancel]",
728 100,
729 this,
730 wxPD_CAN_ABORT |
731 wxPD_APP_MODAL |
732 wxPD_ELAPSED_TIME |
733 wxPD_ESTIMATED_TIME |
734 wxPD_REMAINING_TIME
735 );
736
737 // thread is not running yet, no need for crit sect
738 m_cancelled = FALSE;
739
ce6d2511
RR
740 thread->Run();
741}
742
07f5b19a 743void MyFrame::OnWorkerEvent(wxCommandEvent& event)
ce6d2511 744{
b9de1315 745#if 0
07f5b19a
RR
746 WriteText( "Got message from worker thread: " );
747 WriteText( event.GetString() );
748 WriteText( "\n" );
b9de1315
VZ
749#else
750 int n = event.GetInt();
751 if ( n == -1 )
752 {
753 m_dlgProgress->Destroy();
754 m_dlgProgress = (wxProgressDialog *)NULL;
755
756 // the dialog is aborted because the event came from another thread, so
757 // we may need to wake up the main event loop for the dialog to be
758 // really closed
759 wxWakeUpIdle();
760 }
761 else
762 {
763 if ( !m_dlgProgress->Update(n) )
764 {
765 wxCriticalSectionLocker lock(m_critsectWork);
766
767 m_cancelled = TRUE;
768 }
769 }
770#endif
ce6d2511
RR
771}
772
b9de1315
VZ
773bool MyFrame::Cancelled()
774{
775 wxCriticalSectionLocker lock(m_critsectWork);
776
777 return m_cancelled;
778}