]> git.saurik.com Git - wxWidgets.git/commitdiff
Thread fixes (but they still don't work at all...)
authorVadim Zeitlin <vadim@wxwidgets.org>
Sat, 2 Jan 1999 22:55:03 +0000 (22:55 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sat, 2 Jan 1999 22:55:03 +0000 (22:55 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@1309 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/msw/setup.h
samples/thread/test.cpp
src/msw/app.cpp
src/msw/thread.cpp

index c2dd828953ada7f8927fb5571f855e8e50933611..8612237321a0fd415961f8678967150cb98e3a23 100644 (file)
                                 // Level 1: wxDC, OnSize (etc.) compatibility, but
                                 //          some new features such as event tables
 
-#define wxUSE_AUTOTRANS        1
-                                                               // Define wxTString
+#define wxUSE_AUTOTRANS   1
+                                // Define wxTString
 #define wxUSE_POSTSCRIPT  0
-                               // 0 for no PostScript device context
+                            // 0 for no PostScript device context
 #define wxUSE_AFM_FOR_POSTSCRIPT 0
                                 // 1 to use font metric files in GetTextExtent
 #define wxUSE_METAFILE    1
                                   // since you may well need to output
                                   // an error log in a production
                                   // version (or non-debugging beta)
-#define wxUSE_GLOBAL_MEMORY_OPERATORS 1
+#define wxUSE_GLOBAL_MEMORY_OPERATORS 0
                                   // In debug mode, cause new and delete to be redefined globally.
                                   // If this causes problems (e.g. link errors), set this to 0.
 
                                   // VC++ 4.2 and above allows <iostream> and <iostream.h>
                                   // but you can't mix them. Set to 1 for <iostream.h>,
                                   // 0 for <iostream>
-                      
 
 #define wxUSE_WXCONFIG      1
                                   // if enabled, compiles built-in OS independent wxConfig
                                   // class and it's file (any platform) and registry (Win)
                                   // based implementations
+#define wxUSE_THREADS       1
+                                  // support for multithreaded applications: if
+                                  // 1, compile in thread classes (thread.h)
+                                  // and make the library thread safe
 /*
  * Finer detail
  *
index 071f954478ed68a21489ac28593c20fe7a0eddf1..a2aaaf940c98e19e9ea803871ed202a90a4f5b18 100644 (file)
@@ -6,7 +6,7 @@
 // Created:     06/16/98
 // RCS-ID:      $Id$
 // Copyright:   (c) Julian Smart, Markus Holzem, Guilhem Lavaux
-// Licence:    wxWindows license
+// Licence:     wxWindows license
 /////////////////////////////////////////////////////////////////////////////
 
 #ifdef __GNUG__
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
-#pragma hdrstop
+    #pragma hdrstop
 #endif
 
 #ifndef WX_PRECOMP
-#include "wx/wx.h"
+    #include "wx/wx.h"
 #endif
 
+#if !wxUSE_THREADS
+    #error "This sample requires thread support!"
+#endif // wxUSE_THREADS
+
 #include "wx/thread.h"
 #include "wx/dynarray.h"
+#include "wx/time.h"
 
 // Define a new application type
 class MyApp: public wxApp
@@ -43,7 +48,7 @@ class MyFrame: public wxFrame
 public:
     // ctor
     MyFrame(wxFrame *frame, char *title, int x, int y, int w, int h);
-    
+
     // operations
     void WriteText(const wxString& text) { m_txtctrl->WriteText(text); }
 
@@ -57,14 +62,15 @@ public:
     void OnResumeThread(wxCommandEvent& event);
 
     void OnSize(wxSizeEvent &event);
-    bool OnClose(void) { return TRUE; }
-    
+    void OnIdle(wxIdleEvent &event);
+    bool OnClose() { return TRUE; }
+
 public:
     wxArrayThread m_threads;
 
 private:
     wxTextCtrl *m_txtctrl;
-    
+
     DECLARE_EVENT_TABLE()
 };
 
@@ -72,8 +78,12 @@ class MyThread: public wxThread
 {
 public:
     MyThread(MyFrame *frame);
-    
-    void *Entry();
+
+    // thread execution starts here
+    virtual void *Entry();
+
+    // write something to the text control
+    void WriteText(const wxString& text);
 
 public:
     size_t   m_count;
@@ -87,34 +97,56 @@ MyThread::MyThread(MyFrame *frame)
     m_frame = frame;
 }
 
+void MyThread::WriteText(const wxString& text)
+{
+    wxString msg;
+    msg << wxTime().FormatTime() << ": " << text;
+
+    // before doing any GUI calls we must ensure that this thread is the only
+    // one doing it!
+    wxMutexGuiEnter();
+    m_frame->WriteText(msg);
+    wxMutexGuiLeave();
+}
+
 void *MyThread::Entry()
 {
     wxString text;
-   
+
     DeferDestroy(TRUE);
-    
-    while (1) {
-        TestDestroy();
-        wxMutexGuiEnter();
 
-        text.Printf("[%u] Thread 0x%x here.\n", ++m_count, GetID());
-        m_frame->WriteText(text);
+    text.Printf("Thread 0x%x started.\n", GetID());
+    WriteText(text);
+
+    for ( m_count = 0; m_count < 20; m_count++ )
+    {
+        // check if we were asked to exit
+        if ( TestDestroy() )
+            break;
+
+        text.Printf("[%u] Thread 0x%x here.\n", m_count, GetID());
+        WriteText(text);
 
-        wxMutexGuiLeave();
         wxSleep(1);
     }
-    
+
+    text.Printf("Thread 0x%x finished.\n", GetID());
+    WriteText(text);
+
     return NULL;
 }
 
 // ID for the menu commands
-#define TEST_QUIT        1
-#define TEST_TEXT        101
-#define TEST_ABOUT       102
-#define TEST_START_THREAD 103
-#define TEST_STOP_THREAD  104
-#define TEST_PAUSE_THREAD 105
-#define TEST_RESUME_THREAD 106
+enum
+{
+    TEST_QUIT          = 1,
+    TEST_TEXT          = 101,
+    TEST_ABOUT         = 102,
+    TEST_START_THREAD  = 103,
+    TEST_STOP_THREAD   = 104,
+    TEST_PAUSE_THREAD  = 105,
+    TEST_RESUME_THREAD = 106
+};
 
 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
     EVT_MENU(TEST_QUIT, MyFrame::OnQuit)
@@ -125,40 +157,41 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
     EVT_MENU(TEST_RESUME_THREAD, MyFrame::OnResumeThread)
 
     EVT_SIZE(MyFrame::OnSize)
+
+    EVT_IDLE(MyFrame::OnIdle)
 END_EVENT_TABLE()
 
 // Create a new application object
-IMPLEMENT_APP  (MyApp)
+IMPLEMENT_APP  (MyApp)
 
 // `Main program' equivalent, creating windows and returning main app frame
-bool MyApp::OnInit(void)
+bool MyApp::OnInit()
 {
     // Create the main frame window
-    MyFrame *frame = new MyFrame((wxFrame *) NULL, "wxWindows thread sample",
-                                 50, 50, 450, 340);
-    
+    MyFrame *frame = new MyFrame((wxFrame *)NULL, "", 50, 50, 450, 340);
+
     // Make a menubar
     wxMenu *file_menu = new wxMenu;
-    
+
     file_menu->Append(TEST_ABOUT, "&About");
     file_menu->Append(TEST_QUIT, "E&xit");
     wxMenuBar *menu_bar = new wxMenuBar;
     menu_bar->Append(file_menu, "&File");
-    
+
     wxMenu *thread_menu = new wxMenu;
-    thread_menu->Append(TEST_START_THREAD, "Start a new thread");
-    thread_menu->Append(TEST_STOP_THREAD, "Stop a running thread");
+    thread_menu->Append(TEST_START_THREAD, "&Start a new thread");
+    thread_menu->Append(TEST_STOP_THREAD, "S&top a running thread");
     thread_menu->AppendSeparator();
-    thread_menu->Append(TEST_PAUSE_THREAD, "Pause a running thread");
-    thread_menu->Append(TEST_RESUME_THREAD, "Resume suspended thread");
-    menu_bar->Append(thread_menu, "Thread");
+    thread_menu->Append(TEST_PAUSE_THREAD, "&Pause a running thread");
+    thread_menu->Append(TEST_RESUME_THREAD, "&Resume suspended thread");
+    menu_bar->Append(thread_menu, "&Thread");
     frame->SetMenuBar(menu_bar);
-    
+
     // Show the frame
     frame->Show(TRUE);
-    
+
     SetTopWindow(frame);
-    
+
     return TRUE;
 }
 
@@ -167,8 +200,8 @@ MyFrame::MyFrame(wxFrame *frame, char *title, int x, int y, int w, int h)
        : wxFrame(frame, -1, title, wxPoint(x, y), wxSize(w, h))
 {
     wxPanel *panel = new wxPanel(this, -1, wxPoint(0, 0), wxSize(400, 200),
-                                 wxTAB_TRAVERSAL );
-    
+                                 wxTAB_TRAVERSAL);
+
     m_txtctrl = new wxTextCtrl(panel, -1, "", wxPoint(10,30), wxSize(390, 190),
                                wxTE_MULTILINE);
 
@@ -178,30 +211,30 @@ MyFrame::MyFrame(wxFrame *frame, char *title, int x, int y, int w, int h)
 void MyFrame::OnStartThread(wxCommandEvent& WXUNUSED(event) )
 {
     MyThread *thread = new MyThread(this);
-    
+
     thread->Create();
-    
+
     m_threads.Add(thread);
 }
 
 void MyFrame::OnStopThread(wxCommandEvent& WXUNUSED(event) )
 {
     int no_thrd = m_threads.Count()-1;
-    
+
     if (no_thrd < 0)
         return;
-    
-    delete (m_threads[no_thrd]);
+
+    delete m_threads[no_thrd];
     m_threads.Remove(no_thrd);
 }
 
 void MyFrame::OnResumeThread(wxCommandEvent& WXUNUSED(event) )
 {
-    // resume first suspended thread 
+    // resume first suspended thread
     size_t n = 0;
     while ( n < m_threads.Count() && m_threads[n]->IsPaused() )
         n--;
-    
+
     if ( n < 0 )
         wxLogError("No thread to pause!");
     else
@@ -210,39 +243,58 @@ void MyFrame::OnResumeThread(wxCommandEvent& WXUNUSED(event) )
 
 void MyFrame::OnPauseThread(wxCommandEvent& WXUNUSED(event) )
 {
-    // pause last running thread 
+    // pause last running thread
     int n = m_threads.Count() - 1;
     while ( n >= 0 && !m_threads[n]->IsRunning() )
         n--;
-    
+
     if ( n < 0 )
         wxLogError("No thread to pause!");
     else
         m_threads[n]->Pause();
 }
 
-void MyFrame::OnSize(wxSizeEvent& event )
+// set the frame title indicating the current number of threads
+void MyFrame::OnIdle(wxIdleEvent &event)
+{
+    size_t nRunning = 0,
+           nCount = m_threads.Count();
+    for ( size_t n = 0; n < nCount; n++ )
+    {
+        if ( m_threads[n]->IsRunning() )
+            nRunning++;
+    }
+
+    wxString title;
+    title.Printf("wxWindows thread sample (%u threads, %u running).",
+                 nCount, nRunning);
+    SetTitle(title);
+}
+
+void MyFrame::OnSize(wxSizeEvent& event)
 {
     wxFrame::OnSize(event);
-    
+
     wxSize size( GetClientSize() );
-    
+
     m_txtctrl->SetSize( 10, 30, size.x-20, size.y-40 );
 }
 
 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event) )
 {
-    unsigned int i;
-    for (i=0;i<m_threads.Count();i++)
-        delete (m_threads[i]);
+    for ( size_t i = 0; i < m_threads.Count(); i++ )
+        delete m_threads[i];
+
     Close(TRUE);
 }
 
 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event) )
 {
-    wxMessageDialog dialog(this, "wxThread sample (based on minimal)\nJulian Smart and Guilhem Lavaux",
-        "About wxThread sample", wxYES_NO|wxCANCEL);
-    
+    wxMessageDialog dialog(this, "wxThread sample (based on minimal)\n"
+                                 "Julian Smart and Guilhem Lavaux",
+                           "About wxThread sample",
+                           wxOK | wxICON_INFORMATION);
+
     dialog.ShowModal();
 }
 
index 5ff01965bf8052bbe060a8e495bbfceae070b1f6..ba4d4271a38e98c497c94f32b0c0aac218a372f8 100644 (file)
@@ -38,6 +38,7 @@
 #include "wx/msw/private.h"
 #include "wx/log.h"
 #include "wx/module.h"
+#include "wx/thread.h"
 
 #if wxUSE_WX_RESOURCES
   #include "wx/resource.h"
@@ -844,45 +845,52 @@ bool wxApp::ProcessMessage(WXMSG *Msg)
 
 void wxApp::OnIdle(wxIdleEvent& event)
 {
-  static bool inOnIdle = FALSE;
+    static bool s_inOnIdle = FALSE;
 
-  // Avoid recursion (via ProcessEvent default case)
-  if (inOnIdle)
-    return;
+    // Avoid recursion (via ProcessEvent default case)
+    if ( s_inOnIdle )
+        return;
 
-  inOnIdle = TRUE;
+    s_inOnIdle = TRUE;
 
-  // 'Garbage' collection of windows deleted with Close().
-  DeletePendingObjects();
+    // 'Garbage' collection of windows deleted with Close().
+    DeletePendingObjects();
 
-  // flush the logged messages if any
-  wxLog *pLog = wxLog::GetActiveTarget();
-  if ( pLog != NULL && pLog->HasPendingMessages() )
-    pLog->Flush();
+    // flush the logged messages if any
+    wxLog *pLog = wxLog::GetActiveTarget();
+    if ( pLog != NULL && pLog->HasPendingMessages() )
+        pLog->Flush();
 
-  // Send OnIdle events to all windows
-  bool needMore = SendIdleEvents();
-//  bool needMore = FALSE;
+    // Send OnIdle events to all windows
+    if ( SendIdleEvents() )
+    {
+        // SendIdleEvents() returns TRUE if at least one window requested more
+        // idle events
+        event.RequestMore(TRUE);
+    }
 
-  if (needMore)
-    event.RequestMore(TRUE);
+    // give a chance to all other threads to perform GUI calls
+    wxMutexGuiLeave();
+    ::Sleep(0);
+    wxMutexGuiEnter();
 
-  inOnIdle = FALSE;
+    s_inOnIdle = FALSE;
 }
 
 // Send idle event to all top-level windows
 bool wxApp::SendIdleEvents()
 {
     bool needMore = FALSE;
-  wxNode* node = wxTopLevelWindows.First();
-  while (node)
-  {
-    wxWindow* win = (wxWindow*) node->Data();
-    if (SendIdleEvents(win))
+    wxNode* node = wxTopLevelWindows.First();
+    while (node)
+    {
+        wxWindow* win = (wxWindow*) node->Data();
+        if (SendIdleEvents(win))
             needMore = TRUE;
 
-    node = node->Next();
-  }
+        node = node->Next();
+    }
+
     return needMore;
 }
 
index 56fe00d322a76b32b1ac02c21d4023ea722a549f..d9582324560a0e6b14aa82d43c46a79a9729049e 100644 (file)
 /////////////////////////////////////////////////////////////////////////////
 
 #ifdef __GNUG__
-#pragma implementation "thread.h"
+    #pragma implementation "thread.h"
 #endif
 
-// this is here to regen the precompiled header in the ide compile otherwise the
-// compiler crashes in vc5 (nfi why)
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
 #if defined(__BORLANDC__)
-#pragma hdrstop
+    #pragma hdrstop
 #endif
 
 #ifndef WX_PRECOMP
-#include "wx/wx.h"
+    #include "wx/wx.h"
 #endif
 
+#if wxUSE_THREADS
+
 #include <stdio.h>
 
 #include <windows.h>
+
 #include "wx/module.h"
 #include "wx/thread.h"
 
-enum thread_state {
-  STATE_IDLE = 0,
-  STATE_RUNNING,
-  STATE_CANCELED,
-  STATE_EXITED
+enum thread_state
+{
+    STATE_IDLE = 0,
+    STATE_RUNNING,
+    STATE_CANCELED,
+    STATE_EXITED
 };
 
-/////////////////////////////////////////////////////////////////////////////
-// Static variables
-/////////////////////////////////////////////////////////////////////////////
+// ----------------------------------------------------------------------------
+// static variables
+// ----------------------------------------------------------------------------
 
-static HANDLE p_mainid;
-wxMutex *wxMainMutex; // controls access to all GUI functions
+// id of the main thread - the one which can call GUI functions without first
+// calling wxMutexGuiEnter()
+static HANDLE s_idMainThread;
 
-/////////////////////////////////////////////////////////////////////////////
-// Windows implementation
-/////////////////////////////////////////////////////////////////////////////
+// critical section which controls access to all GUI functions: any secondary
+// thread (i.e. except the main one) must enter this crit section before doing
+// any GUI calls
+static wxCriticalSection *s_critsectGui;
 
-class wxMutexInternal {
+// ============================================================================
+// Windows implementation of thread classes
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// wxMutex implementation
+// ----------------------------------------------------------------------------
+class wxMutexInternal
+{
 public:
-  HANDLE p_mutex;
+    HANDLE p_mutex;
 };
 
 wxMutex::wxMutex()
 {
-  p_internal = new wxMutexInternal;
-  p_internal->p_mutex = CreateMutex(NULL, FALSE, NULL);
-  if ( !p_internal->p_mutex )
-  {
-    wxLogSysError(_("Can not create mutex."));
-  }
+    p_internal = new wxMutexInternal;
+    p_internal->p_mutex = CreateMutex(NULL, FALSE, NULL);
+    if ( !p_internal->p_mutex )
+    {
+        wxLogSysError(_("Can not create mutex."));
+    }
 
-  m_locked = 0;
+    m_locked = 0;
 }
 
 wxMutex::~wxMutex()
 {
-  if (m_locked > 0)
-    wxLogDebug("Warning: freeing a locked mutex (%d locks).", m_locked);
-  CloseHandle(p_internal->p_mutex);
+    if (m_locked > 0)
+        wxLogDebug("Warning: freeing a locked mutex (%d locks).", m_locked);
+    CloseHandle(p_internal->p_mutex);
 }
 
 wxMutexError wxMutex::Lock()
 {
-  DWORD ret;
+    DWORD ret;
+
+    ret = WaitForSingleObject(p_internal->p_mutex, INFINITE);
+    switch ( ret )
+    {
+        case WAIT_ABANDONED:
+            return wxMUTEX_BUSY;
+
+        case WAIT_OBJECT_0:
+            // ok
+            break;
 
-  ret = WaitForSingleObject(p_internal->p_mutex, INFINITE);
-  if (ret == WAIT_ABANDONED)
-    return wxMUTEX_BUSY;
+        case WAIT_FAILED:
+            wxLogSysError(_("Couldn't acquire a mutex lock"));
+            return wxMUTEX_MISC_ERROR;
 
-  m_locked++;
-  return wxMUTEX_NO_ERROR;
+        case WAIT_TIMEOUT:
+        default:
+            wxFAIL_MSG("impossible return value in wxMutex::Lock");
+    }
+
+    m_locked++;
+    return wxMUTEX_NO_ERROR;
 }
 
 wxMutexError wxMutex::TryLock()
 {
-  DWORD ret;
+    DWORD ret;
 
-  ret = WaitForSingleObject(p_internal->p_mutex, 0);
-  if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED)
-    return wxMUTEX_BUSY;
+    ret = WaitForSingleObject(p_internal->p_mutex, 0);
+    if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED)
+        return wxMUTEX_BUSY;
 
-  m_locked++;
-  return wxMUTEX_NO_ERROR;
+    m_locked++;
+    return wxMUTEX_NO_ERROR;
 }
 
 wxMutexError wxMutex::Unlock()
 {
-  if (m_locked > 0)
-    m_locked--;
+    if (m_locked > 0)
+        m_locked--;
 
-  BOOL ret = ReleaseMutex(p_internal->p_mutex);
-  if ( ret != 0 )
-  {
-      wxLogSysError(_("Couldn't release a mutex"));
-      return wxMUTEX_MISC_ERROR;
-  }
+    BOOL ret = ReleaseMutex(p_internal->p_mutex);
+    if ( ret == 0 )
+    {
+        wxLogSysError(_("Couldn't release a mutex"));
+        return wxMUTEX_MISC_ERROR;
+    }
 
-  return wxMUTEX_NO_ERROR;
+    return wxMUTEX_NO_ERROR;
 }
 
-class wxConditionInternal {
+// ----------------------------------------------------------------------------
+// wxCondition implementation
+// ----------------------------------------------------------------------------
+
+class wxConditionInternal
+{
 public:
-  HANDLE event;
-  int waiters;
+    HANDLE event;
+    int waiters;
 };
 
 wxCondition::wxCondition()
 {
-  p_internal = new wxConditionInternal;
-  p_internal->event = CreateEvent(NULL, FALSE, FALSE, NULL);
-  if ( !p_internal->event )
-  {
-    wxLogSysError(_("Can not create event object."));
-  }
+    p_internal = new wxConditionInternal;
+    p_internal->event = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if ( !p_internal->event )
+    {
+        wxLogSysError(_("Can not create event object."));
+    }
 
-  p_internal->waiters = 0;
+    p_internal->waiters = 0;
 }
 
 wxCondition::~wxCondition()
 {
-  CloseHandle(p_internal->event);
+    CloseHandle(p_internal->event);
 }
 
 void wxCondition::Wait(wxMutex& mutex)
 {
-  mutex.Unlock();
-  p_internal->waiters++;
-  WaitForSingleObject(p_internal->event, INFINITE);
-  p_internal->waiters--;
-  mutex.Lock();
+    mutex.Unlock();
+    p_internal->waiters++;
+    WaitForSingleObject(p_internal->event, INFINITE);
+    p_internal->waiters--;
+    mutex.Lock();
 }
 
-bool wxCondition::Wait(wxMutex& mutex, unsigned long sec,
+bool wxCondition::Wait(wxMutex& mutex,
+                       unsigned long sec,
                        unsigned long nsec)
 {
-  DWORD ret;
+    DWORD ret;
 
-  mutex.Unlock();
-  p_internal->waiters++;
-  ret = WaitForSingleObject(p_internal->event, (sec*1000)+(nsec/1000000));
-  p_internal->waiters--;
-  mutex.Lock();
+    mutex.Unlock();
+    p_internal->waiters++;
+    ret = WaitForSingleObject(p_internal->event, (sec*1000)+(nsec/1000000));
+    p_internal->waiters--;
+    mutex.Lock();
 
-  return (ret != WAIT_TIMEOUT);
+    return (ret != WAIT_TIMEOUT);
 }
 
 void wxCondition::Signal()
 {
-  SetEvent(p_internal->event);
+    SetEvent(p_internal->event);
 }
 
 void wxCondition::Broadcast()
 {
-  int i;
+    int i;
 
-  for (i=0;i<p_internal->waiters;i++)
-  {
-    if ( SetEvent(p_internal->event) == 0 )
+    for (i=0;i<p_internal->waiters;i++)
     {
-        wxLogSysError(_("Couldn't change the state of event object."));
+        if ( SetEvent(p_internal->event) == 0 )
+        {
+            wxLogSysError(_("Couldn't change the state of event object."));
+        }
     }
-  }
 }
 
-class wxThreadInternal {
+// ----------------------------------------------------------------------------
+// wxCriticalSection implementation
+// ----------------------------------------------------------------------------
+
+class wxCriticalSectionInternal
+{
+public:
+    // init the critical section object
+    wxCriticalSectionInternal()
+        { ::InitializeCriticalSection(&m_data); }
+
+    // implicit cast to the associated data
+    operator CRITICAL_SECTION *() { return &m_data; }
+
+    // free the associated ressources
+    ~wxCriticalSectionInternal()
+        { ::DeleteCriticalSection(&m_data); }
+
+private:
+    CRITICAL_SECTION m_data;
+};
+
+wxCriticalSection::wxCriticalSection()
+{
+    m_critsect = new wxCriticalSectionInternal;
+}
+
+wxCriticalSection::~wxCriticalSection()
+{
+    delete m_critsect;
+}
+
+void wxCriticalSection::Enter()
+{
+    ::EnterCriticalSection(*m_critsect);
+}
+
+void wxCriticalSection::Leave()
+{
+    ::LeaveCriticalSection(*m_critsect);
+}
+
+// ----------------------------------------------------------------------------
+// wxThread implementation
+// ----------------------------------------------------------------------------
+
+class wxThreadInternal
+{
 public:
-  static DWORD WinThreadStart(LPVOID arg);
+    static DWORD WinThreadStart(LPVOID arg);
 
-  HANDLE thread_id;
-  int state;
-  int prio, defer;
-  DWORD tid;
+    HANDLE thread_id;
+    int state;
+    int prio, defer;
+    DWORD tid;
 };
 
 DWORD wxThreadInternal::WinThreadStart(LPVOID arg)
 {
-  wxThread *ptr = (wxThread *)arg;
-  DWORD ret;
+    wxThread *ptr = (wxThread *)arg;
+    DWORD ret;
 
-  ret = (DWORD)ptr->Entry();
-  ptr->p_internal->state = STATE_EXITED;
+    ret = (DWORD)ptr->Entry();
+    ptr->p_internal->state = STATE_EXITED;
 
-  return ret;
+    return ret;
 }
 
 wxThreadError wxThread::Create()
 {
-  int prio = p_internal->prio;
-
-  p_internal->thread_id = CreateThread(NULL, 0,
-                   (LPTHREAD_START_ROUTINE)wxThreadInternal::WinThreadStart,
-                   (void *)this, CREATE_SUSPENDED, &p_internal->tid);
-
-  if ( p_internal->thread_id == NULL )
-  {
-    wxLogSysError(_("Can't create thread"));
-    return wxTHREAD_NO_RESOURCE;
-  }
-
-  int win_prio;
-  if (prio <= 20)
-    win_prio = THREAD_PRIORITY_LOWEST;
-  else if (prio <= 40)
-    win_prio = THREAD_PRIORITY_BELOW_NORMAL;
-  else if (prio <= 60)
-    win_prio = THREAD_PRIORITY_NORMAL;
-  else if (prio <= 80)
-    win_prio = THREAD_PRIORITY_ABOVE_NORMAL;
-  else if (prio <= 100)
-    win_prio = THREAD_PRIORITY_HIGHEST;
-  else
-  {
-    wxFAIL_MSG("invalid value of thread priority parameter");
-    win_prio = THREAD_PRIORITY_NORMAL;
-  }
-
-  SetThreadPriority(p_internal->thread_id, win_prio);
-
-  ResumeThread(p_internal->thread_id);
-  p_internal->state = STATE_RUNNING;
-  return wxTHREAD_NO_ERROR;
+    int prio = p_internal->prio;
+
+    p_internal->thread_id = CreateThread(NULL, 0,
+            (LPTHREAD_START_ROUTINE)wxThreadInternal::WinThreadStart,
+            (void *)this, CREATE_SUSPENDED, &p_internal->tid);
+
+    if ( p_internal->thread_id == NULL )
+    {
+        wxLogSysError(_("Can't create thread"));
+        return wxTHREAD_NO_RESOURCE;
+    }
+
+    int win_prio;
+    if (prio <= 20)
+        win_prio = THREAD_PRIORITY_LOWEST;
+    else if (prio <= 40)
+        win_prio = THREAD_PRIORITY_BELOW_NORMAL;
+    else if (prio <= 60)
+        win_prio = THREAD_PRIORITY_NORMAL;
+    else if (prio <= 80)
+        win_prio = THREAD_PRIORITY_ABOVE_NORMAL;
+    else if (prio <= 100)
+        win_prio = THREAD_PRIORITY_HIGHEST;
+    else
+    {
+        wxFAIL_MSG("invalid value of thread priority parameter");
+        win_prio = THREAD_PRIORITY_NORMAL;
+    }
+
+    SetThreadPriority(p_internal->thread_id, win_prio);
+
+    ResumeThread(p_internal->thread_id);
+    p_internal->state = STATE_RUNNING;
+
+    return wxTHREAD_NO_ERROR;
 }
 
 wxThreadError wxThread::Destroy()
 {
-  if (p_internal->state != STATE_RUNNING)
-    return wxTHREAD_NOT_RUNNING;
+    if (p_internal->state != STATE_RUNNING)
+        return wxTHREAD_NOT_RUNNING;
 
-  if (p_internal->defer == FALSE)
-    TerminateThread(p_internal->thread_id, 0);
-  else
-    p_internal->state = STATE_CANCELED;
+    if ( p_internal->defer )
+        // soft termination: just set the flag and wait until the thread
+        // auto terminates
+        p_internal->state = STATE_CANCELED;
+    else
+        // kill the thread
+        TerminateThread(p_internal->thread_id, 0);
 
-  return wxTHREAD_NO_ERROR;
+    return wxTHREAD_NO_ERROR;
 }
 
 wxThreadError wxThread::Pause()
@@ -278,121 +365,136 @@ wxThreadError wxThread::Resume()
 
 void wxThread::Exit(void *status)
 {
-  p_internal->state = STATE_EXITED;
-  ExitThread((DWORD)status);
+    p_internal->state = STATE_EXITED;
+    ExitThread((DWORD)status);
 }
 
 void wxThread::SetPriority(int prio)
 {
-  p_internal->prio = prio;
+    p_internal->prio = prio;
 }
 
 int wxThread::GetPriority() const
 {
-  return p_internal->prio;
+    return p_internal->prio;
 }
 
 void wxThread::DeferDestroy(bool on)
 {
-  p_internal->defer = on;
+    p_internal->defer = on;
 }
 
-void wxThread::TestDestroy()
+bool wxThread::TestDestroy()
 {
-  if (p_internal->state == STATE_CANCELED)
-    ExitThread(0);
+    return p_internal->state == STATE_CANCELED;
 }
 
 void *wxThread::Join()
 {
-  DWORD exit_code;
+    DWORD exit_code;
 
-  if (p_internal->state == STATE_IDLE)
-    return NULL;
+    if (p_internal->state == STATE_IDLE)
+        return NULL;
 
-  if (wxThread::IsMain())
-    wxMainMutex->Unlock();
-  WaitForSingleObject(p_internal->thread_id, INFINITE);
-  if (wxThread::IsMain())
-    wxMainMutex->Lock();
+    if (wxThread::IsMain())
+        s_critsectGui->Leave();
+    WaitForSingleObject(p_internal->thread_id, INFINITE);
+    if (wxThread::IsMain())
+        s_critsectGui->Enter();
 
-  GetExitCodeThread(p_internal->thread_id, &exit_code);
-  CloseHandle(p_internal->thread_id);
+    GetExitCodeThread(p_internal->thread_id, &exit_code);
+    CloseHandle(p_internal->thread_id);
 
-  p_internal->state = STATE_IDLE;
+    p_internal->state = STATE_IDLE;
 
-  return (void *)exit_code;
+    return (void *)exit_code;
 }
 
 unsigned long wxThread::GetID() const
 {
-  return (unsigned long)p_internal->tid;
+    return (unsigned long)p_internal->tid;
 }
 
 bool wxThread::IsRunning() const
 {
-  return (p_internal->state == STATE_RUNNING);
+    return (p_internal->state == STATE_RUNNING);
 }
 
 bool wxThread::IsAlive() const
 {
-  return (p_internal->state == STATE_RUNNING);
+    return (p_internal->state == STATE_RUNNING);
 }
 
 bool wxThread::IsMain()
 {
-  return (GetCurrentThread() == p_mainid);
+    return (GetCurrentThread() == s_idMainThread);
 }
 
 wxThread::wxThread()
 {
-  p_internal = new wxThreadInternal();
+    p_internal = new wxThreadInternal();
 
-  p_internal->defer = FALSE;
-  p_internal->prio  = WXTHREAD_DEFAULT_PRIORITY;
-  p_internal->state = STATE_IDLE;
+    p_internal->defer = FALSE;
+    p_internal->prio  = WXTHREAD_DEFAULT_PRIORITY;
+    p_internal->state = STATE_IDLE;
 }
 
 wxThread::~wxThread()
 {
-  Destroy();
-  Join();
-  delete p_internal;
+    Destroy();
+    Join();
+    delete p_internal;
 }
 
-// The default callback just joins the thread and throws away the result.
 void wxThread::OnExit()
 {
-  Join();
 }
 
-// GUI mutex functions
+// ----------------------------------------------------------------------------
+// Automatic initialization for thread module
+// ----------------------------------------------------------------------------
 
-void WXDLLEXPORT wxMutexGuiEnter()
+class wxThreadModule : public wxModule
 {
-  wxFAIL_MSG("not implemented");
-}
-
-void WXDLLEXPORT wxMutexGuiLeave()
-{
-  wxFAIL_MSG("not implemented");
-}
+public:
+    virtual bool OnInit();
+    virtual void OnExit();
 
-// Automatic initialization
+private:
+    DECLARE_DYNAMIC_CLASS(wxThreadModule)
+};
 
 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
 
-bool wxThreadModule::OnInit() 
+bool wxThreadModule::OnInit()
 {
-    wxMainMutex = new wxMutex();
-    p_mainid = GetCurrentThread();
-    wxMainMutex->Lock();
+    s_critsectGui = new wxCriticalSection();
+    s_critsectGui->Enter();
+    s_idMainThread = GetCurrentThread();
+
     return TRUE;
 }
 
-void wxThreadModule::OnExit() 
+void wxThreadModule::OnExit()
 {
-    wxMainMutex->Unlock();
-    delete wxMainMutex;
-};
+    if ( s_critsectGui )
+    {
+        s_critsectGui->Leave();
+        delete s_critsectGui;
+        s_critsectGui = NULL;
+    }
+}
+
+// under Windows, these functions are implemented usign a critical section and
+// not a mutex, so the names are a bit confusing
+void WXDLLEXPORT wxMutexGuiEnter()
+{
+    //s_critsectGui->Enter();
+}
+
+void WXDLLEXPORT wxMutexGuiLeave()
+{
+    //s_critsectGui->Leave();
+}
 
+#endif // wxUSE_THREADS