wxMutex changes (explicitly specify the type), return values for all wxMutex/wxSemaphore/wxCondition methods and general cleanup

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@15761 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2002-06-06 18:31:59 +00:00
parent b0e5c03934
commit 9e84b84742
4 changed files with 957 additions and 985 deletions

View File

@@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////////
// Name: thread.h
// Name: wx/thread.h
// Purpose: Thread API
// Author: Guilhem Lavaux
// Modified by: Vadim Zeitlin (modifications partly inspired by omnithreads
@@ -10,15 +10,15 @@
// 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
@@ -40,11 +40,30 @@
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
@@ -71,6 +90,37 @@ enum
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 WXDLLEXPORT wxConditionInternal;
class WXDLLEXPORT wxMutexInternal;
class WXDLLEXPORT wxSemaphoreInternal;
class WXDLLEXPORT 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
@@ -80,34 +130,44 @@ enum
// you should consider wxMutexLocker whenever possible instead of directly
// working with wxMutex class - it is safer
class WXDLLEXPORT wxConditionInternal;
class WXDLLEXPORT wxMutexInternal;
class WXDLLEXPORT 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.
// Unlock the mutex. It is an error to unlock an already unlocked mutex
wxMutexError Unlock();
// Returns true if the mutex is locked.
bool IsLocked() const { return (m_locked > 0); }
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:
@@ -148,17 +208,11 @@ private:
// 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_IS_MUTEX 0
#endif // MSW/!MSW
@@ -168,50 +222,62 @@ class WXDLLEXPORT wxCriticalSection
{
public:
// ctor & dtor
WXCRITICAL_INLINE wxCriticalSection();
WXCRITICAL_INLINE ~wxCriticalSection();
inline wxCriticalSection();
inline ~wxCriticalSection();
// enter the section (the same as locking a mutex)
WXCRITICAL_INLINE void Enter();
inline void Enter();
// leave the critical section (same as unlocking a mutex)
WXCRITICAL_INLINE void Leave();
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
//
// if CRITICAL_SECTION size changes in Windows, you'll get an assert from
// thread.cpp and will need to increase the buffer size
char m_buffer[24];
#elif !defined(__WXPM__)
wxCriticalSectionInternal *m_critsect;
#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
// wxCriticalSectionLocker is the same to critical sections as wxMutexLocker is
// to th mutexes
class WXDLLEXPORT wxCriticalSectionLocker
{
public:
inline wxCriticalSectionLocker(wxCriticalSection& critsect);
inline ~wxCriticalSectionLocker();
wxCriticalSectionLocker(wxCriticalSection& cs)
: m_critsect(cs)
{
m_critsect.Enter();
}
~wxCriticalSectionLocker()
{
m_critsect.Leave();
}
private:
// no assignment operator nor copy ctor
wxCriticalSectionLocker(const wxCriticalSectionLocker&);
wxCriticalSectionLocker& operator=(const wxCriticalSectionLocker&);
wxCriticalSection& m_critsect;
DECLARE_NO_COPY_CLASS(wxCriticalSectionLocker)
};
// ----------------------------------------------------------------------------
@@ -221,25 +287,24 @@ private:
class WXDLLEXPORT wxCondition
{
DECLARE_NO_COPY_CLASS(wxCondition)
public:
// constructor and destructor
// Each wxCondition object is associated with with a wxMutex object The
// mutex object MUST be locked before calling Wait()
// 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();
// 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.
void Wait();
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
@@ -248,7 +313,7 @@ public:
//
// the timeeout parameter specifies a interval that needs to be waited in
// milliseconds
bool Wait( unsigned long timeout_millis );
wxCondError WaitTimeout(unsigned long milliseconds);
// NB: the associated mutex may or may not be locked by the calling thread
//
@@ -256,7 +321,7 @@ public:
// 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
void Signal();
wxCondError Signal();
// NB: the associated mutex may or may not be locked by the calling thread
//
@@ -264,10 +329,17 @@ public:
// 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.
void Broadcast();
wxCondError Broadcast();
// 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)
};
// ----------------------------------------------------------------------------
@@ -275,11 +347,8 @@ private:
// a shared resource
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxSemaphoreInternal;
class WXDLLEXPORT wxSemaphore
{
DECLARE_NO_COPY_CLASS(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
@@ -288,24 +357,29 @@ public:
// 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())
void Wait();
wxSemaError Wait();
// same as Wait(), but does not block, returns TRUE if successful and
// FALSE if the count is zero
bool TryWait();
// 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 TRUE if the semaphore
// was acquired and FALSE if the timeout has ellapsed
bool Wait( unsigned long timeout_millis );
// 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
void Post();
wxSemaError Post();
private:
wxSemaphoreInternal *m_internal;
DECLARE_NO_COPY_CLASS(wxSemaphore)
};
// ----------------------------------------------------------------------------
@@ -328,7 +402,6 @@ private:
typedef unsigned long wxThreadIdType;
#endif
class wxThreadInternal;
class WXDLLEXPORT wxThread
{
public:
@@ -508,8 +581,6 @@ void WXDLLEXPORT wxMutexGuiLeave();
#else // !wxUSE_THREADS
#include "wx/defs.h" // for WXDLLEXPORT
// no thread support
inline void WXDLLEXPORT wxMutexGuiEnter() { }
inline void WXDLLEXPORT wxMutexGuiLeave() { }
@@ -521,9 +592,9 @@ inline void WXDLLEXPORT wxMutexGuiLeave() { }
#define wxCRIT_SECT_DECLARE(cs)
#define wxCRIT_SECT_LOCKER(name, cs)
#endif // wxUSE_THREADS
#endif // wxUSE_THREADS/!wxUSE_THREADS
// automatically unlock GUI mutex in dtor
// automatically lock GUI mutex in ctor and unlock it in dtor
class WXDLLEXPORT wxMutexGuiLocker
{
public:
@@ -537,7 +608,7 @@ public:
#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
@@ -546,61 +617,17 @@ public:
// returns TRUE if the main thread has GUI lock
extern bool WXDLLEXPORT wxGuiOwnedByMainThread();
#ifndef __WXPM__
// wakes up the main thread if it's sleeping inside ::GetMessage()
extern void WXDLLEXPORT 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();
#elif defined(__WXMAC__)
extern void WXDLLEXPORT wxMutexGuiLeaveOrEnter();
#endif // MSW, Mac, OS/2
// 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();
// implement wxCriticalSection using mutexes
inline wxCriticalSection::wxCriticalSection() : m_mutex() { }
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();
// 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
// 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_