/////////////////////////////////////////////////////////////////////////////
-// Name: thread.h
+// Name: wx/thread.h
// Purpose: Thread API
// Author: Guilhem Lavaux
// Modified by: Vadim Zeitlin (modifications partly inspired by omnithreads
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
-#ifndef __THREADH__
-#define __THREADH__
+#ifndef _WX_THREAD_H_
+#define _WX_THREAD_H_
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// get the value of wxUSE_THREADS configuration flag
-#include "wx/setup.h"
+#include "wx/defs.h"
#if wxUSE_THREADS
// only for wxUSE_THREADS - otherwise we'd get undefined symbols
-#ifdef __GNUG__
+#if defined(__GNUG__) && !defined(__APPLE__)
#pragma interface "thread.h"
#endif
#undef Yield
#endif
-#include "wx/module.h"
-
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
enum wxMutexError
{
- wxMUTEX_NO_ERROR = 0,
- wxMUTEX_DEAD_LOCK, // Mutex has been already locked by THE CALLING thread
- wxMUTEX_BUSY, // Mutex has been already locked by ONE thread
- wxMUTEX_UNLOCKED,
- wxMUTEX_MISC_ERROR
+ wxMUTEX_NO_ERROR = 0, // operation completed successfully
+ wxMUTEX_INVALID, // mutex hasn't been initialized
+ wxMUTEX_DEAD_LOCK, // mutex is already locked by the calling thread
+ wxMUTEX_BUSY, // mutex is already locked by another thread
+ wxMUTEX_UNLOCKED, // attempt to unlock a mutex which is not locked
+ wxMUTEX_MISC_ERROR // any other error
+};
+
+enum wxCondError
+{
+ wxCOND_NO_ERROR = 0,
+ wxCOND_INVALID,
+ wxCOND_TIMEOUT, // WaitTimeout() has timed out
+ wxCOND_MISC_ERROR
+};
+
+enum wxSemaError
+{
+ wxSEMA_NO_ERROR = 0,
+ wxSEMA_INVALID, // semaphore hasn't been initialized successfully
+ wxSEMA_BUSY, // returned by TryWait() if Wait() would block
+ wxSEMA_TIMEOUT, // returned by WaitTimeout()
+ wxSEMA_OVERFLOW, // Post() would increase counter past the max
+ wxSEMA_MISC_ERROR
};
enum wxThreadError
WXTHREAD_MAX_PRIORITY = 100u
};
+// There are 2 types of mutexes: normal mutexes and recursive ones. The attempt
+// to lock a normal mutex by a thread which already owns it results in
+// undefined behaviour (it always works under Windows, it will almost always
+// result in a deadlock under Unix). Locking a recursive mutex in such
+// situation always succeeds and it must be unlocked as many times as it has
+// been locked.
+//
+// However recursive mutexes have several important drawbacks: first, in the
+// POSIX implementation, they're less efficient. Second, and more importantly,
+// they CAN NOT BE USED WITH CONDITION VARIABLES under Unix! Using them with
+// wxCondition will work under Windows and some Unices (notably Linux) but will
+// deadlock under other Unix versions (e.g. Solaris). As it might be difficult
+// to ensure that a recursive mutex is not used with wxCondition, it is a good
+// idea to avoid using recursive mutexes at all. Also, the last problem with
+// them is that some (older) Unix versions don't support this at all -- which
+// results in a configure warning when building and a deadlock when using them.
+enum wxMutexType
+{
+ // normal mutex: try to always use this one
+ wxMUTEX_DEFAULT,
+
+ // recursive mutex: don't use these ones with wxCondition
+ wxMUTEX_RECURSIVE
+};
+
+// forward declarations
+class WXDLLIMPEXP_BASE wxThreadHelper;
+class WXDLLIMPEXP_BASE wxConditionInternal;
+class WXDLLIMPEXP_BASE wxMutexInternal;
+class WXDLLIMPEXP_BASE wxSemaphoreInternal;
+class WXDLLIMPEXP_BASE wxThreadInternal;
+
// ----------------------------------------------------------------------------
// A mutex object is a synchronization object whose state is set to signaled
// when it is not owned by any thread, and nonsignaled when it is owned. Its
// you should consider wxMutexLocker whenever possible instead of directly
// working with wxMutex class - it is safer
-class WXDLLEXPORT wxMutexInternal;
-class WXDLLEXPORT wxMutex
+class WXDLLIMPEXP_BASE wxMutex
{
public:
// constructor & destructor
- wxMutex();
+ // ------------------------
+
+ // create either default (always safe) or recursive mutex
+ wxMutex(wxMutexType mutexType = wxMUTEX_DEFAULT);
+
+ // destroys the mutex kernel object
~wxMutex();
- // Lock the mutex.
+ // test if the mutex has been created successfully
+ bool IsOk() const;
+
+ // mutex operations
+ // ----------------
+
+ // Lock the mutex, blocking on it until it is unlocked by the other thread.
+ // The result of locking a mutex already locked by the current thread
+ // depend on the mutex type.
+ //
+ // The caller must call Unlock() later if Lock() returned wxMUTEX_NO_ERROR.
wxMutexError Lock();
- // Try to lock the mutex: if it can't, returns immediately with an error.
+
+ // Try to lock the mutex: if it is currently locked, return immediately
+ // with an error. Otherwise the caller must call Unlock().
wxMutexError TryLock();
- // Unlock the mutex.
- wxMutexError Unlock();
- // Returns true if the mutex is locked.
- bool IsLocked() const { return (m_locked > 0); }
+ // Unlock the mutex. It is an error to unlock an already unlocked mutex
+ wxMutexError Unlock();
protected:
- // no assignment operator nor copy ctor
- wxMutex(const wxMutex&);
- wxMutex& operator=(const wxMutex&);
-
- int m_locked;
wxMutexInternal *m_internal;
+
+ friend class wxConditionInternal;
+
+ DECLARE_NO_COPY_CLASS(wxMutex)
};
// a helper class which locks the mutex in the ctor and unlocks it in the dtor:
// this ensures that mutex is always unlocked, even if the function returns or
// throws an exception before it reaches the end
-class WXDLLEXPORT wxMutexLocker
+class WXDLLIMPEXP_BASE wxMutexLocker
{
public:
// lock the mutex in the ctor
- wxMutexLocker(wxMutex& mutex) : m_mutex(mutex)
- { m_isOk = m_mutex.Lock() == wxMUTEX_NO_ERROR; }
+ wxMutexLocker(wxMutex& mutex)
+ : m_isOk(FALSE), m_mutex(mutex)
+ { m_isOk = ( m_mutex.Lock() == wxMUTEX_NO_ERROR ); }
// returns TRUE if mutex was successfully locked in ctor
bool IsOk() const
// which makes it possible to have static globals of this class
// ----------------------------------------------------------------------------
-class WXDLLEXPORT wxCriticalSectionInternal;
-
// in order to avoid any overhead under platforms where critical sections are
// just mutexes make all wxCriticalSection class functions inline
#if !defined(__WXMSW__) && !defined(__WXPM__)
- #define WXCRITICAL_INLINE inline
-
#define wxCRITSECT_IS_MUTEX 1
-#else // MSW || OS2
- #define WXCRITICAL_INLINE
+ #define wxCRITSECT_INLINE inline
+#else // MSW || OS2
#define wxCRITSECT_IS_MUTEX 0
+
+ #define wxCRITSECT_INLINE
#endif // MSW/!MSW
// you should consider wxCriticalSectionLocker whenever possible instead of
// directly working with wxCriticalSection class - it is safer
-class WXDLLEXPORT wxCriticalSection
+class WXDLLIMPEXP_BASE wxCriticalSection
{
public:
// ctor & dtor
- WXCRITICAL_INLINE wxCriticalSection();
- WXCRITICAL_INLINE ~wxCriticalSection();
+ wxCRITSECT_INLINE wxCriticalSection();
+ wxCRITSECT_INLINE ~wxCriticalSection();
// enter the section (the same as locking a mutex)
- WXCRITICAL_INLINE void Enter();
+ wxCRITSECT_INLINE void Enter();
+
// leave the critical section (same as unlocking a mutex)
- WXCRITICAL_INLINE void Leave();
+ wxCRITSECT_INLINE void Leave();
private:
- // no assignment operator nor copy ctor
- wxCriticalSection(const wxCriticalSection&);
- wxCriticalSection& operator=(const wxCriticalSection&);
-
#if wxCRITSECT_IS_MUTEX
wxMutex m_mutex;
#elif defined(__WXMSW__)
// we can't allocate any memory in the ctor, so use placement new -
// unfortunately, we have to hardcode the sizeof() here because we can't
- // include windows.h from this public header
- char m_buffer[24];
-#elif !defined(__WXPM__)
- wxCriticalSectionInternal *m_critsect;
+ // include windows.h from this public header and we also have to use the
+ // union to force the correct (i.e. maximal) alignment
+ //
+ // if CRITICAL_SECTION size changes in Windows, you'll get an assert from
+ // thread.cpp and will need to increase the buffer size
+ //
+ // finally, we need this typedef instead of declaring m_buffer directly
+ // because otherwise the assert mentioned above wouldn't compile with some
+ // compilers (notably CodeWarrior 8)
+ typedef char wxCritSectBuffer[24];
+ union
+ {
+ unsigned long m_dummy1;
+ void *m_dummy2;
+
+ wxCritSectBuffer m_buffer;
+ };
#else
// nothing for OS/2
-#endif // !Unix/Unix
+#endif // Unix/Win32/OS2
+
+ DECLARE_NO_COPY_CLASS(wxCriticalSection)
};
-// keep your preprocessor name space clean
-#undef WXCRITICAL_INLINE
+#if wxCRITSECT_IS_MUTEX
+ // implement wxCriticalSection using mutexes
+ inline wxCriticalSection::wxCriticalSection() { }
+ inline wxCriticalSection::~wxCriticalSection() { }
+
+ inline void wxCriticalSection::Enter() { (void)m_mutex.Lock(); }
+ inline void wxCriticalSection::Leave() { (void)m_mutex.Unlock(); }
+#endif // wxCRITSECT_IS_MUTEX
+
+#undef wxCRITSECT_INLINE
+#undef wxCRITSECT_IS_MUTEX
// wxCriticalSectionLocker is the same to critical sections as wxMutexLocker is
// to th mutexes
-class WXDLLEXPORT wxCriticalSectionLocker
+class WXDLLIMPEXP_BASE wxCriticalSectionLocker
{
public:
- inline wxCriticalSectionLocker(wxCriticalSection& critsect);
- inline ~wxCriticalSectionLocker();
+ wxCriticalSectionLocker(wxCriticalSection& cs)
+ : m_critsect(cs)
+ {
+ m_critsect.Enter();
+ }
-private:
- // no assignment operator nor copy ctor
- wxCriticalSectionLocker(const wxCriticalSectionLocker&);
- wxCriticalSectionLocker& operator=(const wxCriticalSectionLocker&);
+ ~wxCriticalSectionLocker()
+ {
+ m_critsect.Leave();
+ }
+private:
wxCriticalSection& m_critsect;
+
+ DECLARE_NO_COPY_CLASS(wxCriticalSectionLocker)
};
// ----------------------------------------------------------------------------
-// Condition variable: allows to block the thread execution until something
-// happens (== condition is signaled)
+// wxCondition models a POSIX condition variable which allows one (or more)
+// thread(s) to wait until some condition is fulfilled
// ----------------------------------------------------------------------------
-class wxConditionInternal;
-class WXDLLEXPORT wxCondition
+class WXDLLIMPEXP_BASE wxCondition
{
public:
- // constructor & destructor
- wxCondition();
+ // Each wxCondition object is associated with a (single) wxMutex object.
+ // The mutex object MUST be locked before calling Wait()
+ wxCondition(wxMutex& mutex);
+
+ // dtor is not virtual, don't use this class polymorphically
~wxCondition();
- // wait until the condition is signaled
- // waits indefinitely.
- void Wait();
- // waits until a signal is raised or the timeout elapses
- bool Wait(unsigned long sec, unsigned long nsec);
+ // return TRUE if the condition has been created successfully
+ bool IsOk() const;
+
+ // NB: the associated mutex MUST be locked beforehand by the calling thread
+ //
+ // it atomically releases the lock on the associated mutex
+ // and starts waiting to be woken up by a Signal()/Broadcast()
+ // once its signaled, then it will wait until it can reacquire
+ // the lock on the associated mutex object, before returning.
+ wxCondError Wait();
+
+ // exactly as Wait() except that it may also return if the specified
+ // timeout ellapses even if the condition hasn't been signalled: in this
+ // case, the return value is FALSE, otherwise (i.e. in case of a normal
+ // return) it is TRUE
+ //
+ // the timeeout parameter specifies a interval that needs to be waited in
+ // milliseconds
+ wxCondError WaitTimeout(unsigned long milliseconds);
+
+ // NB: the associated mutex may or may not be locked by the calling thread
+ //
+ // this method unblocks one thread if any are blocking on the condition.
+ // if no thread is blocking in Wait(), then the signal is NOT remembered
+ // The thread which was blocking on Wait(), will then reacquire the lock
+ // on the associated mutex object before returning
+ wxCondError Signal();
+
+ // NB: the associated mutex may or may not be locked by the calling thread
+ //
+ // this method unblocks all threads if any are blocking on the condition.
+ // if no thread is blocking in Wait(), then the signal is NOT remembered
+ // The threads which were blocking on Wait(), will then reacquire the lock
+ // on the associated mutex object before returning.
+ wxCondError Broadcast();
- // signal the condition
- // wakes up one (and only one) of the waiting threads
- void Signal();
- // wakes up all threads waiting on this condition
- void Broadcast();
-#ifdef __WXDEBUG__
- // for debugging purposes only
- void *GetId() const { return m_internal; }
-#endif // __WXDEBUG__
+ // deprecated version, don't use
+ bool Wait(unsigned long milliseconds)
+ { return WaitTimeout(milliseconds) == wxCOND_NO_ERROR; }
private:
wxConditionInternal *m_internal;
+
+ DECLARE_NO_COPY_CLASS(wxCondition)
};
// ----------------------------------------------------------------------------
-// Thread class
+// wxSemaphore: a counter limiting the number of threads concurrently accessing
+// a shared resource
+// ----------------------------------------------------------------------------
+
+class WXDLLIMPEXP_BASE wxSemaphore
+{
+public:
+ // specifying a maxcount of 0 actually makes wxSemaphore behave as if there
+ // is no upper limit, if maxcount is 1 the semaphore behaves as a mutex
+ wxSemaphore( int initialcount = 0, int maxcount = 0 );
+
+ // dtor is not virtual, don't use this class polymorphically
+ ~wxSemaphore();
+
+ // return TRUE if the semaphore has been created successfully
+ bool IsOk() const;
+
+ // wait indefinitely, until the semaphore count goes beyond 0
+ // and then decrement it and return (this method might have been called
+ // Acquire())
+ wxSemaError Wait();
+
+ // same as Wait(), but does not block, returns wxSEMA_NO_ERROR if
+ // successful and wxSEMA_BUSY if the count is currently zero
+ wxSemaError TryWait();
+
+ // same as Wait(), but as a timeout limit, returns wxSEMA_NO_ERROR if the
+ // semaphore was acquired and wxSEMA_TIMEOUT if the timeout has ellapsed
+ wxSemaError WaitTimeout(unsigned long milliseconds);
+
+ // increments the semaphore count and signals one of the waiting threads
+ wxSemaError Post();
+
+private:
+ wxSemaphoreInternal *m_internal;
+
+ DECLARE_NO_COPY_CLASS(wxSemaphore)
+};
+
+// ----------------------------------------------------------------------------
+// wxThread: class encpasulating a thread of execution
// ----------------------------------------------------------------------------
// there are two different kinds of threads: joinable and detached (default)
typedef unsigned long wxThreadIdType;
#endif
-class wxThreadInternal;
-class WXDLLEXPORT wxThread
+class WXDLLIMPEXP_BASE wxThread
{
public:
// the return type for the thread function
bool m_isDetached;
};
+// wxThreadHelperThread class
+// --------------------------
+
+class WXDLLIMPEXP_BASE wxThreadHelperThread : public wxThread
+{
+public:
+ // constructor only creates the C++ thread object and doesn't create (or
+ // start) the real thread
+ wxThreadHelperThread(wxThreadHelper& owner)
+ : wxThread(wxTHREAD_JOINABLE), m_owner(owner)
+ { }
+
+protected:
+ // entry point for the thread -- calls Entry() in owner.
+ virtual void *Entry();
+
+private:
+ // the owner of the thread
+ wxThreadHelper& m_owner;
+
+ // no copy ctor/assignment operator
+ wxThreadHelperThread(const wxThreadHelperThread&);
+ wxThreadHelperThread& operator=(const wxThreadHelperThread&);
+};
+
+// ----------------------------------------------------------------------------
+// wxThreadHelper: this class implements the threading logic to run a
+// background task in another object (such as a window). It is a mix-in: just
+// derive from it to implement a threading background task in your class.
+// ----------------------------------------------------------------------------
+
+class WXDLLIMPEXP_BASE wxThreadHelper
+{
+private:
+ void KillThread()
+ {
+ if ( m_thread )
+ {
+ m_thread->Kill();
+ delete m_thread;
+ }
+ }
+
+public:
+ // constructor only initializes m_thread to NULL
+ wxThreadHelper() : m_thread(NULL) { }
+
+ // destructor deletes m_thread
+ virtual ~wxThreadHelper() { KillThread(); }
+
+ // create a new thread (and optionally set the stack size on platforms that
+ // support/need that), call Run() to start it
+ wxThreadError Create(unsigned int stackSize = 0)
+ {
+ KillThread();
+
+ m_thread = new wxThreadHelperThread(*this);
+
+ return m_thread->Create(stackSize);
+ }
+
+ // entry point for the thread - called by Run() and executes in the context
+ // of this thread.
+ virtual void *Entry() = 0;
+
+ // returns a pointer to the thread which can be used to call Run()
+ wxThread *GetThread() const { return m_thread; }
+
+protected:
+ wxThread *m_thread;
+};
+
+// call Entry() in owner, put it down here to avoid circular declarations
+inline void *wxThreadHelperThread::Entry()
+{
+ return m_owner.Entry();
+}
+
// ----------------------------------------------------------------------------
// Automatic initialization
// ----------------------------------------------------------------------------
// GUI mutex handling.
-void WXDLLEXPORT wxMutexGuiEnter();
-void WXDLLEXPORT wxMutexGuiLeave();
+void WXDLLIMPEXP_BASE wxMutexGuiEnter();
+void WXDLLIMPEXP_BASE wxMutexGuiLeave();
// macros for entering/leaving critical sections which may be used without
// having to take them inside "#if wxUSE_THREADS"
#define wxENTER_CRIT_SECT(cs) (cs).Enter()
#define wxLEAVE_CRIT_SECT(cs) (cs).Leave()
#define wxCRIT_SECT_DECLARE(cs) static wxCriticalSection cs
+#define wxCRIT_SECT_DECLARE_MEMBER(cs) wxCriticalSection cs
#define wxCRIT_SECT_LOCKER(name, cs) wxCriticalSectionLocker name(cs)
-#else // !wxUSE_THREADS
+// function for checking if we're in the main thread which may be used whether
+// wxUSE_THREADS is 0 or 1
+inline bool wxIsMainThread() { return wxThread::IsMain(); }
-#include "wx/defs.h" // for WXDLLEXPORT
+#else // !wxUSE_THREADS
// no thread support
-inline void WXDLLEXPORT wxMutexGuiEnter() { }
-inline void WXDLLEXPORT wxMutexGuiLeave() { }
+inline void WXDLLIMPEXP_BASE wxMutexGuiEnter() { }
+inline void WXDLLIMPEXP_BASE wxMutexGuiLeave() { }
// macros for entering/leaving critical sections which may be used without
// having to take them inside "#if wxUSE_THREADS"
#define wxENTER_CRIT_SECT(cs)
#define wxLEAVE_CRIT_SECT(cs)
#define wxCRIT_SECT_DECLARE(cs)
+#define wxCRIT_SECT_DECLARE_MEMBER(cs)
#define wxCRIT_SECT_LOCKER(name, cs)
-#endif // wxUSE_THREADS
+// if there is only one thread, it is always the main one
+inline bool wxIsMainThread() { return true; }
-// automatically unlock GUI mutex in dtor
-class WXDLLEXPORT wxMutexGuiLocker
+#endif // wxUSE_THREADS/!wxUSE_THREADS
+
+// mark part of code as being a critical section: this macro declares a
+// critical section with the given name and enters it immediately and leaves
+// it at the end of the current scope
+//
+// example:
+//
+// int Count()
+// {
+// static int s_counter = 0;
+//
+// wxCRITICAL_SECTION(counter);
+//
+// return ++s_counter;
+// }
+//
+// this function is MT-safe in presence of the threads but there is no
+// overhead when the library is compiled without threads
+#define wxCRITICAL_SECTION(name) \
+ wxCRIT_SECT_DECLARE(s_cs##name); \
+ wxCRIT_SECT_LOCKER(cs##name##Locker, s_cs##name)
+
+// automatically lock GUI mutex in ctor and unlock it in dtor
+class WXDLLIMPEXP_BASE wxMutexGuiLocker
{
public:
wxMutexGuiLocker() { wxMutexGuiEnter(); }
#if wxUSE_THREADS
-#if defined(__WXMSW__)
+#if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXPM__)
// unlock GUI if there are threads waiting for and lock it back when
// there are no more of them - should be called periodically by the main
// thread
- extern void WXDLLEXPORT wxMutexGuiLeaveOrEnter();
-
- // returns TRUE if the main thread has GUI lock
- extern bool WXDLLEXPORT wxGuiOwnedByMainThread();
-
- // wakes up the main thread if it's sleeping inside ::GetMessage()
- extern void WXDLLEXPORT wxWakeUpMainThread();
-
- // return TRUE if the main thread is waiting for some other to terminate:
- // wxApp then should block all "dangerous" messages
- extern bool WXDLLEXPORT wxIsWaitingForThread();
-#elif defined(__WXMAC__)
- extern void WXDLLEXPORT wxMutexGuiLeaveOrEnter();
+ extern void WXDLLIMPEXP_BASE wxMutexGuiLeaveOrEnter();
// returns TRUE if the main thread has GUI lock
- extern bool WXDLLEXPORT wxGuiOwnedByMainThread();
+ extern bool WXDLLIMPEXP_BASE wxGuiOwnedByMainThread();
+#ifndef __WXPM__
// wakes up the main thread if it's sleeping inside ::GetMessage()
- extern void WXDLLEXPORT wxWakeUpMainThread();
-
- // return TRUE if the main thread is waiting for some other to terminate:
- // wxApp then should block all "dangerous" messages
- extern bool WXDLLEXPORT wxIsWaitingForThread();
-
- // implement wxCriticalSection using mutexes
- inline wxCriticalSection::wxCriticalSection() { }
- inline wxCriticalSection::~wxCriticalSection() { }
-
- inline void wxCriticalSection::Enter() { (void)m_mutex.Lock(); }
- inline void wxCriticalSection::Leave() { (void)m_mutex.Unlock(); }
-#elif defined(__WXPM__)
- // unlock GUI if there are threads waiting for and lock it back when
- // there are no more of them - should be called periodically by the main
- // thread
- extern void WXDLLEXPORT wxMutexGuiLeaveOrEnter();
-
- // returns TRUE if the main thread has GUI lock
- extern bool WXDLLEXPORT wxGuiOwnedByMainThread();
+ extern void WXDLLIMPEXP_BASE wxWakeUpMainThread();
+#endif // !OS/2
// return TRUE if the main thread is waiting for some other to terminate:
// wxApp then should block all "dangerous" messages
- extern bool WXDLLEXPORT wxIsWaitingForThread();
-
-#else // !MSW && !PM
- // implement wxCriticalSection using mutexes
- inline wxCriticalSection::wxCriticalSection() { }
- inline wxCriticalSection::~wxCriticalSection() { }
-
- inline void wxCriticalSection::Enter() { (void)m_mutex.Lock(); }
- inline void wxCriticalSection::Leave() { (void)m_mutex.Unlock(); }
-#endif // MSW/!MSW
+ extern bool WXDLLIMPEXP_BASE wxIsWaitingForThread();
+#endif // MSW, Mac, OS/2
- // we can define these inline functions now (they should be defined after
- // wxCriticalSection::Enter/Leave)
- inline
- wxCriticalSectionLocker:: wxCriticalSectionLocker(wxCriticalSection& cs)
- : m_critsect(cs) { m_critsect.Enter(); }
- inline
- wxCriticalSectionLocker::~wxCriticalSectionLocker() { m_critsect.Leave(); }
#endif // wxUSE_THREADS
-#endif // __THREADH__
+#endif // _WX_THREAD_H_
-// vi:sts=4:sw=4:et