]> git.saurik.com Git - wxWidgets.git/blobdiff - samples/thread/thread.cpp
don't use deprecated toolbar API
[wxWidgets.git] / samples / thread / thread.cpp
index 161df995ff21fc711cc7d5bb88fa1fdc4d498838..078442a78605ceb7c63915ed4795f19456605f2b 100644 (file)
@@ -1,11 +1,11 @@
 /////////////////////////////////////////////////////////////////////////////
 // Name:        thread.cpp
 /////////////////////////////////////////////////////////////////////////////
 // Name:        thread.cpp
-// Purpose:     wxWindows thread sample
+// Purpose:     wxWidgets thread sample
 // Author:      Guilhem Lavaux, Vadim Zeitlin
 // Modified by:
 // Created:     06/16/98
 // RCS-ID:      $Id$
 // Author:      Guilhem Lavaux, Vadim Zeitlin
 // Modified by:
 // Created:     06/16/98
 // RCS-ID:      $Id$
-// Copyright:   (c) 1998-2002 wxWindows team
+// Copyright:   (c) 1998-2002 wxWidgets team
 // Licence:     wxWindows license
 /////////////////////////////////////////////////////////////////////////////
 
 // Licence:     wxWindows license
 /////////////////////////////////////////////////////////////////////////////
 
 
 #include "wx/thread.h"
 #include "wx/dynarray.h"
 
 #include "wx/thread.h"
 #include "wx/dynarray.h"
-#include "wx/time.h"
+#include "wx/numdlg.h"
 
 #include "wx/progdlg.h"
 
 
 #include "wx/progdlg.h"
 
+#include "../sample.xpm"
+
 // define this to use wxExecute in the exec tests, otherwise just use system
 #define USE_EXECUTE
 
 // define this to use wxExecute in the exec tests, otherwise just use system
 #define USE_EXECUTE
 
 #endif
 
 class MyThread;
 #endif
 
 class MyThread;
-WX_DEFINE_ARRAY(wxThread *, wxArrayThread);
+WX_DEFINE_ARRAY_PTR(wxThread *, wxArrayThread);
 
 // Define a new application type
 class MyApp : public wxApp
 {
 public:
     MyApp();
 
 // Define a new application type
 class MyApp : public wxApp
 {
 public:
     MyApp();
-    virtual ~MyApp();
+    virtual ~MyApp(){};
 
     virtual bool OnInit();
 
 
     virtual bool OnInit();
 
-public:
+    // critical section protects access to all of the fields below
+    wxCriticalSection m_critsect;
+
     // all the threads currently alive - as soon as the thread terminates, it's
     // removed from the array
     wxArrayThread m_threads;
 
     // all the threads currently alive - as soon as the thread terminates, it's
     // removed from the array
     wxArrayThread m_threads;
 
-    // crit section protects access to all of the arrays below
-    wxCriticalSection m_critsect;
-
-    // the (mutex, condition) pair used to wait for the threads to exit, see
-    // MyFrame::OnQuit()
-    wxMutex m_mutexAllDone;
-    wxCondition m_condAllDone;
+    // semaphore used to wait for the threads to exit, see MyFrame::OnQuit()
+    wxSemaphore m_semAllDone;
 
 
-    // the last exiting thread should signal m_condAllDone if this is true
-    // (protected by the same m_critsect)
-    bool m_waitingUntilAllDone;
+    // indicates that we're shutting down and all threads should exit
+    bool m_shuttingDown;
 };
 
 // Create a new application object
 };
 
 // Create a new application object
@@ -78,15 +76,25 @@ class MyFrame: public wxFrame
 public:
     // ctor
     MyFrame(wxFrame *frame, const wxString& title, int x, int y, int w, int h);
 public:
     // ctor
     MyFrame(wxFrame *frame, const wxString& title, int x, int y, int w, int h);
+    virtual ~MyFrame();
 
 
-    // operations
-    void WriteText(const wxString& text) { m_txtctrl->WriteText(text); }
+    // this function is MT-safe, i.e. it can be called from worker threads
+    // safely without any additional locking
+    void LogThreadMessage(const wxString& text)
+    {
+        wxCriticalSectionLocker lock(m_csMessages);
+        m_messages.push_back(text);
+
+        // as we effectively log the messages from the idle event handler,
+        // ensure it's going to be called now that we have some messages to log
+        wxWakeUpIdle();
+    }
 
     // accessors for MyWorkerThread (called in its context!)
     bool Cancelled();
 
 
     // accessors for MyWorkerThread (called in its context!)
     bool Cancelled();
 
-protected:
-    // callbacks
+private:
+    // event handlers
     void OnQuit(wxCommandEvent& event);
     void OnClear(wxCommandEvent& event);
 
     void OnQuit(wxCommandEvent& event);
     void OnClear(wxCommandEvent& event);
 
@@ -108,15 +116,27 @@ protected:
 
     void OnIdle(wxIdleEvent &event);
 
 
     void OnIdle(wxIdleEvent &event);
 
-private:
     // helper function - creates a new thread (but doesn't run it)
     MyThread *CreateThread();
 
     // helper function - creates a new thread (but doesn't run it)
     MyThread *CreateThread();
 
+    // update display in our status bar: called during idle handling
+    void UpdateThreadStatus();
+
+    // log the messages queued by LogThreadMessage()
+    void DoLogThreadMessages();
+
+
     // just some place to put our messages in
     wxTextCtrl *m_txtctrl;
 
     // just some place to put our messages in
     wxTextCtrl *m_txtctrl;
 
+    // the array of pending messages to be displayed and the critical section
+    // protecting it
+    wxArrayString m_messages;
+    wxCriticalSection m_csMessages;
+
     // remember the number of running threads and total number of threads
     // remember the number of running threads and total number of threads
-    size_t m_nRunning, m_nCount;
+    size_t m_nRunning,
+           m_nCount;
 
     // the progress dialog which we show while worker thread is running
     wxProgressDialog *m_dlgProgress;
 
     // the progress dialog which we show while worker thread is running
     wxProgressDialog *m_dlgProgress;
@@ -133,7 +153,8 @@ private:
 // ID for the menu commands
 enum
 {
 // ID for the menu commands
 enum
 {
-    THREAD_QUIT          = 1,
+    THREAD_QUIT  = wxID_EXIT,
+    THREAD_ABOUT = wxID_ABOUT,
     THREAD_TEXT          = 101,
     THREAD_CLEAR,
     THREAD_START_THREAD  = 201,
     THREAD_TEXT          = 101,
     THREAD_CLEAR,
     THREAD_START_THREAD  = 201,
@@ -147,7 +168,6 @@ enum
     THREAD_EXEC_THREAD,
 
     THREAD_SHOWCPUS,
     THREAD_EXEC_THREAD,
 
     THREAD_SHOWCPUS,
-    THREAD_ABOUT,
 
     WORKER_EVENT    // this one gets sent from the worker thread
 };
 
     WORKER_EVENT    // this one gets sent from the worker thread
 };
@@ -160,19 +180,19 @@ class MyThread : public wxThread
 {
 public:
     MyThread(MyFrame *frame);
 {
 public:
     MyThread(MyFrame *frame);
+    virtual ~MyThread();
 
     // thread execution starts here
     virtual void *Entry();
 
 
     // thread execution starts here
     virtual void *Entry();
 
-    // called when the thread exits - whether it terminates normally or is
-    // stopped with Delete() (but not when it is Kill()ed!)
-    virtual void OnExit();
-
-    // write something to the text control
-    void WriteText(const wxString& text);
+    // write something to the text control in the main frame
+    void WriteText(const wxString& text)
+    {
+        m_frame->LogThreadMessage(text);
+    }
 
 public:
 
 public:
-    size_t   m_count;
+    unsigned m_count;
     MyFrame *m_frame;
 };
 
     MyFrame *m_frame;
 };
 
@@ -183,22 +203,7 @@ MyThread::MyThread(MyFrame *frame)
     m_frame = frame;
 }
 
     m_frame = frame;
 }
 
-void MyThread::WriteText(const wxString& text)
-{
-    wxString msg;
-
-    // before doing any GUI calls we must ensure that this thread is the only
-    // one doing it!
-
-    wxMutexGuiEnter();
-
-    msg << text;
-    m_frame->WriteText(msg);
-
-    wxMutexGuiLeave();
-}
-
-void MyThread::OnExit()
+MyThread::~MyThread()
 {
     wxCriticalSectionLocker locker(wxGetApp().m_critsect);
 
 {
     wxCriticalSectionLocker locker(wxGetApp().m_critsect);
 
@@ -209,12 +214,11 @@ void MyThread::OnExit()
     {
         // signal the main thread that there are no more threads left if it is
         // waiting for us
     {
         // signal the main thread that there are no more threads left if it is
         // waiting for us
-        if ( wxGetApp().m_waitingUntilAllDone )
+        if ( wxGetApp().m_shuttingDown )
         {
         {
-            wxGetApp().m_waitingUntilAllDone = FALSE;
+            wxGetApp().m_shuttingDown = false;
 
 
-            wxMutexLocker lock(wxGetApp().m_mutexAllDone);
-            wxGetApp().m_condAllDone.Signal();
+            wxGetApp().m_semAllDone.Post();
         }
     }
 }
         }
     }
 }
@@ -223,25 +227,33 @@ void *MyThread::Entry()
 {
     wxString text;
 
 {
     wxString text;
 
-    text.Printf(wxT("Thread 0x%x started (priority = %d).\n"),
+    text.Printf(wxT("Thread 0x%lx started (priority = %u).\n"),
                 GetId(), GetPriority());
     WriteText(text);
     // wxLogMessage(text); -- test wxLog thread safeness
 
     for ( m_count = 0; m_count < 10; m_count++ )
     {
                 GetId(), GetPriority());
     WriteText(text);
     // wxLogMessage(text); -- test wxLog thread safeness
 
     for ( m_count = 0; m_count < 10; m_count++ )
     {
-        // check if we were asked to exit
+        // check if the application is shutting down: in this case all threads
+        // should stop a.s.a.p.
+        {
+            wxCriticalSectionLocker locker(wxGetApp().m_critsect);
+            if ( wxGetApp().m_shuttingDown )
+                return NULL;
+        }
+
+        // check if just this thread was asked to exit
         if ( TestDestroy() )
             break;
 
         if ( TestDestroy() )
             break;
 
-        text.Printf(wxT("[%u] Thread 0x%x here.\n"), m_count, GetId());
+        text.Printf(wxT("[%u] Thread 0x%lx here.\n"), m_count, GetId());
         WriteText(text);
 
         // wxSleep() can't be called from non-GUI thread!
         wxThread::Sleep(1000);
     }
 
         WriteText(text);
 
         // wxSleep() can't be called from non-GUI thread!
         wxThread::Sleep(1000);
     }
 
-    text.Printf(wxT("Thread 0x%x finished.\n"), GetId());
+    text.Printf(wxT("Thread 0x%lx finished.\n"), GetId());
     WriteText(text);
     // wxLogMessage(text); -- test wxLog thread safeness
 
     WriteText(text);
     // wxLogMessage(text); -- test wxLog thread safeness
 
@@ -266,7 +278,7 @@ public:
 
 public:
     MyFrame *m_frame;
 
 public:
     MyFrame *m_frame;
-    size_t   m_count;
+    unsigned m_count;
 };
 
 MyWorkerThread::MyWorkerThread(MyFrame *frame)
 };
 
 MyWorkerThread::MyWorkerThread(MyFrame *frame)
@@ -295,8 +307,7 @@ void *MyWorkerThread::Entry()
         // send in a thread-safe way
         wxPostEvent( m_frame, event );
 
         // send in a thread-safe way
         wxPostEvent( m_frame, event );
 
-        // wxSleep() can't be called from non-main thread!
-        wxThread::Sleep(200);
+        wxMilliSleep(200);
     }
 
     wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, WORKER_EVENT );
     }
 
     wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, WORKER_EVENT );
@@ -321,7 +332,7 @@ public:
 
     virtual ExitCode Entry()
     {
 
     virtual ExitCode Entry()
     {
-        return (ExitCode)EXEC(m_command);
+        return wxUIntToPtr(EXEC(m_command));
     }
 
 private:
     }
 
 private:
@@ -355,89 +366,113 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
 END_EVENT_TABLE()
 
 MyApp::MyApp()
 END_EVENT_TABLE()
 
 MyApp::MyApp()
-     : m_condAllDone(m_mutexAllDone)
-{
-    // the mutex associated with a condition must be initially locked, it will
-    // only be unlocked when we call Wait()
-    m_mutexAllDone.Lock();
-
-    m_waitingUntilAllDone = FALSE;
-}
-
-MyApp::~MyApp()
 {
 {
-    // the mutex must be unlocked before being destroyed
-    m_mutexAllDone.Unlock();
+    m_shuttingDown = false;
 }
 
 // `Main program' equivalent, creating windows and returning main app frame
 bool MyApp::OnInit()
 {
 }
 
 // `Main program' equivalent, creating windows and returning main app frame
 bool MyApp::OnInit()
 {
+    if ( !wxApp::OnInit() )
+        return false;
+
     // uncomment this to get some debugging messages from the trace code
     // on the console (or just set WXTRACE env variable to include "thread")
     //wxLog::AddTraceMask("thread");
 
     // Create the main frame window
     // uncomment this to get some debugging messages from the trace code
     // on the console (or just set WXTRACE env variable to include "thread")
     //wxLog::AddTraceMask("thread");
 
     // Create the main frame window
-    MyFrame *frame = new MyFrame((wxFrame *)NULL, "wxWindows threads sample",
+    MyFrame *frame = new MyFrame((wxFrame *)NULL, _T("wxWidgets threads sample"),
                                  50, 50, 450, 340);
 
     // Make a menubar
     wxMenuBar *menuBar = new wxMenuBar;
 
     wxMenu *menuFile = new wxMenu;
                                  50, 50, 450, 340);
 
     // Make a menubar
     wxMenuBar *menuBar = new wxMenuBar;
 
     wxMenu *menuFile = new wxMenu;
-    menuFile->Append(THREAD_CLEAR, "&Clear log\tCtrl-L");
+    menuFile->Append(THREAD_CLEAR, _T("&Clear log\tCtrl-L"));
     menuFile->AppendSeparator();
     menuFile->AppendSeparator();
-    menuFile->Append(THREAD_QUIT, "E&xit\tAlt-X");
-    menuBar->Append(menuFile, "&File");
+    menuFile->Append(THREAD_QUIT, _T("E&xit\tAlt-X"));
+    menuBar->Append(menuFile, _T("&File"));
 
     wxMenu *menuThread = new wxMenu;
 
     wxMenu *menuThread = new wxMenu;
-    menuThread->Append(THREAD_START_THREAD, "&Start a new thread\tCtrl-N");
-    menuThread->Append(THREAD_START_THREADS, "Start &many threads at once");
-    menuThread->Append(THREAD_STOP_THREAD, "S&top a running thread\tCtrl-S");
+    menuThread->Append(THREAD_START_THREAD, _T("&Start a new thread\tCtrl-N"));
+    menuThread->Append(THREAD_START_THREADS, _T("Start &many threads at once"));
+    menuThread->Append(THREAD_STOP_THREAD, _T("S&top a running thread\tCtrl-S"));
     menuThread->AppendSeparator();
     menuThread->AppendSeparator();
-    menuThread->Append(THREAD_PAUSE_THREAD, "&Pause a running thread\tCtrl-P");
-    menuThread->Append(THREAD_RESUME_THREAD, "&Resume suspended thread\tCtrl-R");
+    menuThread->Append(THREAD_PAUSE_THREAD, _T("&Pause a running thread\tCtrl-P"));
+    menuThread->Append(THREAD_RESUME_THREAD, _T("&Resume suspended thread\tCtrl-R"));
     menuThread->AppendSeparator();
     menuThread->AppendSeparator();
-    menuThread->Append(THREAD_START_WORKER, "Start &worker thread\tCtrl-W");
-    menuBar->Append(menuThread, "&Thread");
+    menuThread->Append(THREAD_START_WORKER, _T("Start &worker thread\tCtrl-W"));
+    menuBar->Append(menuThread, _T("&Thread"));
 
     wxMenu *menuExec = new wxMenu;
 
     wxMenu *menuExec = new wxMenu;
-    menuExec->Append(THREAD_EXEC_MAIN, "&Launch a program from main thread\tF5");
-    menuExec->Append(THREAD_EXEC_THREAD, "L&aunch a program from a thread\tCtrl-F5");
-    menuBar->Append(menuExec, "&Execute");
+    menuExec->Append(THREAD_EXEC_MAIN, _T("&Launch a program from main thread\tF5"));
+    menuExec->Append(THREAD_EXEC_THREAD, _T("L&aunch a program from a thread\tCtrl-F5"));
+    menuBar->Append(menuExec, _T("&Execute"));
 
     wxMenu *menuHelp = new wxMenu;
 
     wxMenu *menuHelp = new wxMenu;
-    menuHelp->Append(THREAD_SHOWCPUS, "&Show CPU count");
+    menuHelp->Append(THREAD_SHOWCPUS, _T("&Show CPU count"));
     menuHelp->AppendSeparator();
     menuHelp->AppendSeparator();
-    menuHelp->Append(THREAD_ABOUT, "&About...");
-    menuBar->Append(menuHelp, "&Help");
+    menuHelp->Append(THREAD_ABOUT, _T("&About..."));
+    menuBar->Append(menuHelp, _T("&Help"));
 
     frame->SetMenuBar(menuBar);
 
     frame->SetMenuBar(menuBar);
-
+    
     // Show the frame
     // Show the frame
-    frame->Show(TRUE);
+    frame->Show(true);
 
     SetTopWindow(frame);
 
 
     SetTopWindow(frame);
 
-    return TRUE;
+    return true;
 }
 
 // My frame constructor
 MyFrame::MyFrame(wxFrame *frame, const wxString& title,
                  int x, int y, int w, int h)
 }
 
 // My frame constructor
 MyFrame::MyFrame(wxFrame *frame, const wxString& title,
                  int x, int y, int w, int h)
-       : wxFrame(frame, -1, title, wxPoint(x, y), wxSize(w, h))
+       : wxFrame(frame, wxID_ANY, title, wxPoint(x, y), wxSize(w, h))
 {
 {
+    SetIcon(wxIcon(sample_xpm));
+    
     m_nRunning = m_nCount = 0;
 
     m_dlgProgress = (wxProgressDialog *)NULL;
 
     m_nRunning = m_nCount = 0;
 
     m_dlgProgress = (wxProgressDialog *)NULL;
 
+#if wxUSE_STATUSBAR
     CreateStatusBar(2);
     CreateStatusBar(2);
+#endif // wxUSE_STATUSBAR
 
 
-    m_txtctrl = new wxTextCtrl(this, -1, "", wxPoint(0, 0), wxSize(0, 0),
+    m_txtctrl = new wxTextCtrl(this, wxID_ANY, _T(""), wxPoint(0, 0), wxSize(0, 0),
                                wxTE_MULTILINE | wxTE_READONLY);
 
 }
 
                                wxTE_MULTILINE | wxTE_READONLY);
 
 }
 
+MyFrame::~MyFrame()
+{
+    // NB: although the OS will terminate all the threads anyhow when the main
+    //     one exits, it's good practice to do it ourselves -- even if it's not
+    //     completely trivial in this example
+
+    // tell all the threads to terminate: note that they can't terminate while
+    // we're deleting them because they will block in their OnExit() -- this is
+    // important as otherwise we might access invalid array elements
+
+    {
+        wxCriticalSectionLocker locker(wxGetApp().m_critsect);
+
+        // check if we have any threads running first
+        const wxArrayThread& threads = wxGetApp().m_threads;
+        size_t count = threads.GetCount();
+
+        if ( !count )
+            return;
+
+        // set the flag indicating that all threads should exit
+        wxGetApp().m_shuttingDown = true;
+    }
+
+    // now wait for them to really terminate
+    wxGetApp().m_semAllDone.Wait();
+}
+
 MyThread *MyFrame::CreateThread()
 {
     MyThread *thread = new MyThread(this);
 MyThread *MyFrame::CreateThread()
 {
     MyThread *thread = new MyThread(this);
@@ -455,10 +490,10 @@ MyThread *MyFrame::CreateThread()
 
 void MyFrame::OnStartThreads(wxCommandEvent& WXUNUSED(event) )
 {
 
 void MyFrame::OnStartThreads(wxCommandEvent& WXUNUSED(event) )
 {
-    static long s_num = 10;
+    static long s_num;
 
 
-    s_num = wxGetNumberFromUser("How many threads to start: ", "",
-                                "wxThread sample", s_num, 1, 10000, this);
+    s_num = wxGetNumberFromUser(_T("How many threads to start: "), _T(""),
+                                _T("wxThread sample"), s_num, 1, 10000, this);
     if ( s_num == -1 )
     {
         s_num = 10;
     if ( s_num == -1 )
     {
         s_num = 10;
@@ -466,7 +501,7 @@ void MyFrame::OnStartThreads(wxCommandEvent& WXUNUSED(event) )
         return;
     }
 
         return;
     }
 
-    size_t count = (size_t)s_num, n;
+    unsigned count = unsigned(s_num), n;
 
     wxArrayThread threads;
 
 
     wxArrayThread threads;
 
@@ -488,9 +523,11 @@ void MyFrame::OnStartThreads(wxCommandEvent& WXUNUSED(event) )
         threads.Add(thr);
     }
 
         threads.Add(thr);
     }
 
+#if wxUSE_STATUSBAR
     wxString msg;
     msg.Printf(wxT("%d new threads created."), count);
     SetStatusText(msg, 1);
     wxString msg;
     msg.Printf(wxT("%d new threads created."), count);
     SetStatusText(msg, 1);
+#endif // wxUSE_STATUSBAR
 
     // ...and then start them
     for ( n = 0; n < count; n++ )
 
     // ...and then start them
     for ( n = 0; n < count; n++ )
@@ -508,32 +545,27 @@ void MyFrame::OnStartThread(wxCommandEvent& WXUNUSED(event) )
         wxLogError(wxT("Can't start thread!"));
     }
 
         wxLogError(wxT("Can't start thread!"));
     }
 
-    SetStatusText("New thread started.", 1);
+#if wxUSE_STATUSBAR
+    SetStatusText(_T("New thread started."), 1);
+#endif // wxUSE_STATUSBAR
 }
 
 void MyFrame::OnStopThread(wxCommandEvent& WXUNUSED(event) )
 {
 }
 
 void MyFrame::OnStopThread(wxCommandEvent& WXUNUSED(event) )
 {
-    wxGetApp().m_critsect.Enter();
+    wxCriticalSectionLocker enter(wxGetApp().m_critsect);
 
     // stop the last thread
     if ( wxGetApp().m_threads.IsEmpty() )
     {
         wxLogError(wxT("No thread to stop!"));
 
     // stop the last thread
     if ( wxGetApp().m_threads.IsEmpty() )
     {
         wxLogError(wxT("No thread to stop!"));
-
-        wxGetApp().m_critsect.Leave();
     }
     else
     {
     }
     else
     {
-        wxThread *thread = wxGetApp().m_threads.Last();
+        wxGetApp().m_threads.Last()->Delete();
 
 
-        // it's important to leave critical section before calling Delete()
-        // because delete will (implicitly) call OnExit() which also tries
-        // to enter the same crit section - would dead lock.
-        wxGetApp().m_critsect.Leave();
-
-        thread->Delete();
-
-        SetStatusText("Thread stopped.", 1);
+#if wxUSE_STATUSBAR
+        SetStatusText(_T("Last thread stopped."), 1);
+#endif // wxUSE_STATUSBAR
     }
 }
 
     }
 }
 
@@ -554,7 +586,9 @@ void MyFrame::OnResumeThread(wxCommandEvent& WXUNUSED(event) )
     {
         wxGetApp().m_threads[n]->Resume();
 
     {
         wxGetApp().m_threads[n]->Resume();
 
-        SetStatusText("Thread resumed.", 1);
+#if wxUSE_STATUSBAR
+        SetStatusText(_T("Thread resumed."), 1);
+#endif // wxUSE_STATUSBAR
     }
 }
 
     }
 }
 
@@ -575,12 +609,35 @@ void MyFrame::OnPauseThread(wxCommandEvent& WXUNUSED(event) )
     {
         wxGetApp().m_threads[n]->Pause();
 
     {
         wxGetApp().m_threads[n]->Pause();
 
-        SetStatusText("Thread paused.", 1);
+#if wxUSE_STATUSBAR
+        SetStatusText(_T("Thread paused."), 1);
+#endif // wxUSE_STATUSBAR
+    }
+}
+
+void MyFrame::OnIdle(wxIdleEvent& event)
+{
+    DoLogThreadMessages();
+
+    UpdateThreadStatus();
+
+    event.Skip();
+}
+
+void MyFrame::DoLogThreadMessages()
+{
+    wxCriticalSectionLocker lock(m_csMessages);
+
+    const size_t count = m_messages.size();
+    for ( size_t n = 0; n < count; n++ )
+    {
+        m_txtctrl->AppendText(m_messages[n]);
     }
     }
+
+    m_messages.clear();
 }
 
 }
 
-// set the frame title indicating the current number of threads
-void MyFrame::OnIdle(wxIdleEvent &event)
+void MyFrame::UpdateThreadStatus()
 {
     wxCriticalSectionLocker enter(wxGetApp().m_critsect);
 
 {
     wxCriticalSectionLocker enter(wxGetApp().m_critsect);
 
@@ -598,61 +655,20 @@ void MyFrame::OnIdle(wxIdleEvent &event)
         m_nRunning = nRunning;
         m_nCount = nCount;
 
         m_nRunning = nRunning;
         m_nCount = nCount;
 
-        wxLogStatus(this, wxT("%u threads total, %u running."), nCount, nRunning);
+        wxLogStatus(this, wxT("%u threads total, %u running."), unsigned(nCount), unsigned(nRunning));
     }
     //else: avoid flicker - don't print anything
 }
 
 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event) )
 {
     }
     //else: avoid flicker - don't print anything
 }
 
 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event) )
 {
-    // NB: although the OS will terminate all the threads anyhow when the main
-    //     one exits, it's good practice to do it ourselves -- even if it's not
-    //     completely trivial in this example
-
-    // tell all the threads to terminate: note that they can't terminate while
-    // we're deleting them because they will block in their OnExit() -- this is
-    // important as otherwise we might access invalid array elements
-    {
-        wxGetApp().m_critsect.Enter();
-
-        // check if we have any threads running first
-        const wxArrayThread& threads = wxGetApp().m_threads;
-        size_t count = threads.GetCount();
-
-        if ( count )
-        {
-            // we do, ask them to stop
-            for ( size_t n = 0; n < count; n++ )
-            {
-                threads[n]->Delete();
-            }
-
-            // set the flag for MyThread::OnExit()
-            wxGetApp().m_waitingUntilAllDone = TRUE;
-        }
-
-        wxGetApp().m_critsect.Leave();
-
-        if ( count )
-        {
-            // now wait for them to really terminate but leave the GUI mutex
-            // before doing it as otherwise we might dead lock
-            wxMutexGuiLeave();
-
-            wxGetApp().m_condAllDone.Wait();
-
-            wxMutexGuiEnter();
-        }
-        //else: no threads to terminate, no condition to wait for
-    }
-
-    Close(TRUE);
+    Close(true);
 }
 
 void MyFrame::OnExecMain(wxCommandEvent& WXUNUSED(event))
 {
     wxLogMessage(wxT("The exit code from the main program is %ld"),
 }
 
 void MyFrame::OnExecMain(wxCommandEvent& WXUNUSED(event))
 {
     wxLogMessage(wxT("The exit code from the main program is %ld"),
-                 EXEC("/bin/echo \"main program\""));
+                 EXEC(_T("/bin/echo \"main program\"")));
 }
 
 void MyFrame::OnExecThread(wxCommandEvent& WXUNUSED(event))
 }
 
 void MyFrame::OnExecThread(wxCommandEvent& WXUNUSED(event))
@@ -661,7 +677,7 @@ void MyFrame::OnExecThread(wxCommandEvent& WXUNUSED(event))
     thread.Run();
 
     wxLogMessage(wxT("The exit code from a child thread is %ld"),
     thread.Run();
 
     wxLogMessage(wxT("The exit code from a child thread is %ld"),
-                 (long)thread.Wait());
+                 (long)wxPtrToUInt(thread.Wait()));
 }
 
 void MyFrame::OnShowCPUs(wxCommandEvent& WXUNUSED(event))
 }
 
 void MyFrame::OnShowCPUs(wxCommandEvent& WXUNUSED(event))
@@ -672,31 +688,32 @@ void MyFrame::OnShowCPUs(wxCommandEvent& WXUNUSED(event))
     switch ( nCPUs )
     {
         case -1:
     switch ( nCPUs )
     {
         case -1:
-            msg = "Unknown number of CPUs";
+            msg = _T("Unknown number of CPUs");
             break;
 
         case 0:
             break;
 
         case 0:
-            msg = "WARNING: you're running without any CPUs!";
+            msg = _T("WARNING: you're running without any CPUs!");
             break;
 
         case 1:
             break;
 
         case 1:
-            msg = "This system only has one CPU.";
+            msg = _T("This system only has one CPU.");
             break;
 
         default:
             msg.Printf(wxT("This system has %d CPUs"), nCPUs);
     }
             break;
 
         default:
             msg.Printf(wxT("This system has %d CPUs"), nCPUs);
     }
-            
+
     wxLogMessage(msg);
 }
 
 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event) )
 {
     wxLogMessage(msg);
 }
 
 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event) )
 {
-    wxMessageDialog dialog(this, "wxWindows multithreaded application sample\n"
-                                 "(c) 1998 Julian Smart, Guilhem Lavaux\n"
-                                 "(c) 1999 Vadim Zeitlin\n"
-                                 "(c) 2000 Robert Roebling",
-                           "About wxThread sample",
+    wxMessageDialog dialog(this,
+                           _T("wxWidgets multithreaded application sample\n")
+                           _T("(c) 1998 Julian Smart, Guilhem Lavaux\n")
+                           _T("(c) 1999 Vadim Zeitlin\n")
+                           _T("(c) 2000 Robert Roebling"),
+                           _T("About wxThread sample"),
                            wxOK | wxICON_INFORMATION);
 
     dialog.ShowModal();
                            wxOK | wxICON_INFORMATION);
 
     dialog.ShowModal();
@@ -719,12 +736,13 @@ void MyFrame::OnStartWorker(wxCommandEvent& WXUNUSED(event))
     if ( thread->Create() != wxTHREAD_NO_ERROR )
     {
         wxLogError(wxT("Can't create thread!"));
     if ( thread->Create() != wxTHREAD_NO_ERROR )
     {
         wxLogError(wxT("Can't create thread!"));
+        return;
     }
 
     m_dlgProgress = new wxProgressDialog
                         (
     }
 
     m_dlgProgress = new wxProgressDialog
                         (
-                         "Progress dialog",
-                         "Wait until the thread terminates or press [Cancel]",
+                         _T("Progress dialog"),
+                         _T("Wait until the thread terminates or press [Cancel]"),
                          100,
                          this,
                          wxPD_CAN_ABORT |
                          100,
                          this,
                          wxPD_CAN_ABORT |
@@ -735,18 +753,13 @@ void MyFrame::OnStartWorker(wxCommandEvent& WXUNUSED(event))
                         );
 
     // thread is not running yet, no need for crit sect
                         );
 
     // thread is not running yet, no need for crit sect
-    m_cancelled = FALSE;
+    m_cancelled = false;
 
     thread->Run();
 }
 
 void MyFrame::OnWorkerEvent(wxCommandEvent& event)
 {
 
     thread->Run();
 }
 
 void MyFrame::OnWorkerEvent(wxCommandEvent& event)
 {
-#if 0
-    WriteText( "Got message from worker thread: " );
-    WriteText( event.GetString() );
-    WriteText( "\n" );
-#else
     int n = event.GetInt();
     if ( n == -1 )
     {
     int n = event.GetInt();
     if ( n == -1 )
     {
@@ -764,10 +777,9 @@ void MyFrame::OnWorkerEvent(wxCommandEvent& event)
         {
             wxCriticalSectionLocker lock(m_critsectWork);
 
         {
             wxCriticalSectionLocker lock(m_critsectWork);
 
-            m_cancelled = TRUE;
+            m_cancelled = true;
         }
     }
         }
     }
-#endif
 }
 
 bool MyFrame::Cancelled()
 }
 
 bool MyFrame::Cancelled()