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