From 3222fde2afae240176ca9a3edba853e36b885ddb Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 2 Jan 1999 22:55:03 +0000 Subject: [PATCH] Thread fixes (but they still don't work at all...) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@1309 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/msw/setup.h | 13 +- samples/thread/test.cpp | 172 ++++++++++----- src/msw/app.cpp | 56 +++-- src/msw/thread.cpp | 474 ++++++++++++++++++++++++---------------- 4 files changed, 440 insertions(+), 275 deletions(-) diff --git a/include/wx/msw/setup.h b/include/wx/msw/setup.h index c2dd828953..8612237321 100644 --- a/include/wx/msw/setup.h +++ b/include/wx/msw/setup.h @@ -28,10 +28,10 @@ // 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 @@ -120,7 +120,7 @@ // 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. @@ -149,12 +149,15 @@ // VC++ 4.2 and above allows and // but you can't mix them. Set to 1 for , // 0 for - #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 * diff --git a/samples/thread/test.cpp b/samples/thread/test.cpp index 071f954478..a2aaaf940c 100644 --- a/samples/thread/test.cpp +++ b/samples/thread/test.cpp @@ -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__ @@ -18,15 +18,20 @@ #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;iHasPendingMessages() ) - 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; } diff --git a/src/msw/thread.cpp b/src/msw/thread.cpp index 56fe00d322..d958232456 100644 --- a/src/msw/thread.cpp +++ b/src/msw/thread.cpp @@ -10,244 +10,331 @@ ///////////////////////////////////////////////////////////////////////////// #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 #include + #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;iwaiters;i++) - { - if ( SetEvent(p_internal->event) == 0 ) + for (i=0;iwaiters;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 -- 2.45.2