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