attempts to make wxCondition::Broadcast() work - it still doesn't

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@13919 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2002-01-29 22:49:13 +00:00
parent c22503ddb9
commit 547b93ab04
2 changed files with 113 additions and 69 deletions

View File

@@ -234,7 +234,7 @@ public:
// signal the condition // signal the condition
// wakes up one (and only one) of the waiting threads // wakes up one (and only one) of the waiting threads
void Signal(); void Signal();
// wakes up all threads waiting onthis condition // wakes up all threads waiting on this condition
void Broadcast(); void Broadcast();
private: private:
@@ -254,6 +254,13 @@ private:
// created by the wxThread object while "main thread" is the thread created // created by the wxThread object while "main thread" is the thread created
// during the process initialization (a.k.a. the GUI thread) // during the process initialization (a.k.a. the GUI thread)
// On VMS thread pointers are 64 bits (also needed for other systems???
#ifdef __VMS
typedef unsigned long long wxThreadIdType;
#else
typedef unsigned long wxThreadIdType;
#endif
class wxThreadInternal; class wxThreadInternal;
class WXDLLEXPORT wxThread class WXDLLEXPORT wxThread
{ {
@@ -289,13 +296,8 @@ public:
// Get the platform specific thread ID and return as a long. This // Get the platform specific thread ID and return as a long. This
// can be used to uniquely identify threads, even if they are not // can be used to uniquely identify threads, even if they are not
// wxThreads. This is used by wxPython. // wxThreads. This is used by wxPython.
// On VMS thread pointers are 64 bits (also needed for other systems??? static wxThreadIdType GetCurrentId();
#ifdef __VMS
static unsigned long long GetCurrentId();
#else
static unsigned long GetCurrentId();
#endif
// sets the concurrency level: this is, roughly, the number of threads // sets the concurrency level: this is, roughly, the number of threads
// the system tries to schedule to run in parallel. 0 means the // the system tries to schedule to run in parallel. 0 means the
// default value (usually acceptable, but may not yield the best // default value (usually acceptable, but may not yield the best
@@ -381,11 +383,7 @@ public:
// Get the thread ID - a platform dependent number which uniquely // Get the thread ID - a platform dependent number which uniquely
// identifies a thread inside a process // identifies a thread inside a process
#ifdef __VMS wxThreadIdType GetId() const;
unsigned long long GetId() const;
#else
unsigned long GetId() const;
#endif
// called when the thread exits - in the context of this thread // called when the thread exits - in the context of this thread
// //

View File

@@ -34,13 +34,13 @@
#include "wx/log.h" #include "wx/log.h"
#include "wx/intl.h" #include "wx/intl.h"
#include "wx/dynarray.h" #include "wx/dynarray.h"
#include "wx/listimpl.cpp"
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <pthread.h> #include <pthread.h>
#include <errno.h> #include <errno.h>
#include <time.h> #include <time.h>
#if HAVE_SCHED_H #if HAVE_SCHED_H
#include <sched.h> #include <sched.h>
#endif #endif
@@ -257,6 +257,8 @@ wxMutexError wxMutex::Unlock()
// remember that the condition was signaled and to return from Wait() // remember that the condition was signaled and to return from Wait()
// immediately in this case (this is more like Win32 automatic event objects) // immediately in this case (this is more like Win32 automatic event objects)
WX_DECLARE_LIST(pthread_mutex_t, wxMutexList);
class wxConditionInternal class wxConditionInternal
{ {
public: public:
@@ -269,25 +271,32 @@ public:
void Signal(); void Signal();
void Broadcast(); void Broadcast();
void WaitDone(); void WaitDone(wxMutexList::Node *mutexnode);
bool ShouldWait(); wxMutexList::Node *ShouldWait();
bool HasWaiters(); bool HasWaiters();
private: private:
bool m_wasSignaled; // TRUE if condition was signaled while void LockAllMutexes(); // locks all mutexes on the list
// nobody waited for it void UnlockAllMutexes(); // unlocks mutexes after signaling / broadcasting
size_t m_nWaiters; // TRUE if someone already waits for us
pthread_mutex_t m_mutexProtect; // protects access to vars above // TRUE if condition was signaled while nobody waited for it
bool m_wasSignaled;
pthread_mutex_t m_mutex; // the mutex used with the condition // protects access to vars above
pthread_cond_t m_condition; // the condition itself pthread_mutex_t m_mutexProtect;
// the mutexes which are used for the condition variable
wxMutexList m_mutexes;
// the condition itself
pthread_cond_t m_condition;
}; };
WX_DEFINE_LIST(wxMutexList);
wxConditionInternal::wxConditionInternal() wxConditionInternal::wxConditionInternal()
{ {
m_wasSignaled = FALSE; m_wasSignaled = FALSE;
m_nWaiters = 0;
if ( pthread_cond_init(&m_condition, (pthread_condattr_t *)NULL) != 0 ) if ( pthread_cond_init(&m_condition, (pthread_condattr_t *)NULL) != 0 )
{ {
@@ -295,19 +304,12 @@ wxConditionInternal::wxConditionInternal()
wxFAIL_MSG( _T("pthread_cond_init() failed") ); wxFAIL_MSG( _T("pthread_cond_init() failed") );
} }
if ( pthread_mutex_init(&m_mutex, (pthread_mutexattr_t *)NULL) != 0 || if ( pthread_mutex_init(&m_mutexProtect, NULL) != 0 )
pthread_mutex_init(&m_mutexProtect, NULL) != 0 )
{ {
// neither this // neither this
wxFAIL_MSG( _T("wxCondition: pthread_mutex_init() failed") ); wxFAIL_MSG( _T("wxCondition: pthread_mutex_init() failed") );
} }
// initially the mutex is locked, so no thread can Signal() or Broadcast()
// until another thread starts to Wait()
if ( pthread_mutex_lock(&m_mutex) != 0 )
{
wxFAIL_MSG( _T("wxCondition: pthread_mutex_lock() failed") );
}
} }
wxConditionInternal::~wxConditionInternal() wxConditionInternal::~wxConditionInternal()
@@ -318,27 +320,40 @@ wxConditionInternal::~wxConditionInternal()
"threads are probably still waiting on it?)")); "threads are probably still waiting on it?)"));
} }
if ( pthread_mutex_unlock( &m_mutex ) != 0 ) for ( wxMutexList::Node *node = m_mutexes.GetFirst();
node;
node = node->GetNext() )
{ {
wxLogDebug(_T("wxCondition: failed to unlock the mutex")); pthread_mutex_t *currentmutex = node->GetData();
if ( pthread_mutex_unlock( currentmutex ) != 0 )
{
wxLogDebug(_T("wxCondition: failed to unlock the mutex"));
} else {
delete currentmutex;
}
} }
if ( pthread_mutex_destroy( &m_mutex ) != 0 || m_mutexes.DeleteContents(TRUE);
pthread_mutex_destroy( &m_mutexProtect ) != 0 )
if ( pthread_mutex_destroy( &m_mutexProtect ) != 0 )
{ {
wxLogDebug(_T("Failed to destroy mutex (it is probably locked)")); wxLogDebug(_T("Failed to destroy mutex (it is probably locked)"));
} }
} }
void wxConditionInternal::WaitDone() void wxConditionInternal::WaitDone(wxMutexList::Node *mutexnode)
{ {
MutexLock lock(m_mutexProtect); MutexLock lock(m_mutexProtect);
m_wasSignaled = FALSE; pthread_mutex_unlock(mutexnode->GetData());
m_nWaiters--; pthread_mutex_destroy(mutexnode->GetData());
delete mutexnode->GetData();
m_mutexes.DeleteNode(mutexnode);
} }
bool wxConditionInternal::ShouldWait() wxMutexList::Node *wxConditionInternal::ShouldWait()
{ {
MutexLock lock(m_mutexProtect); MutexLock lock(m_mutexProtect);
@@ -348,20 +363,26 @@ bool wxConditionInternal::ShouldWait()
// flag and return // flag and return
m_wasSignaled = FALSE; m_wasSignaled = FALSE;
return FALSE; return NULL;
} }
// we start to wait for it // we start to wait for it
m_nWaiters++;
return TRUE; pthread_mutex_t *waitmutex = new pthread_mutex_t;
if ( pthread_mutex_init(waitmutex, (pthread_mutexattr_t *)NULL) != 0 )
{
// neither this
wxFAIL_MSG( _T("wxCondition: pthread_mutex_init() failed when starting waiting") );
}
pthread_mutex_lock(waitmutex);
return ( m_mutexes.Append(waitmutex) );
} }
bool wxConditionInternal::HasWaiters() bool wxConditionInternal::HasWaiters()
{ {
MutexLock lock(m_mutexProtect); if ( m_mutexes.GetCount() )
if ( m_nWaiters )
{ {
// someone waits for us, signal the condition normally // someone waits for us, signal the condition normally
return TRUE; return TRUE;
@@ -376,25 +397,29 @@ bool wxConditionInternal::HasWaiters()
void wxConditionInternal::Wait() void wxConditionInternal::Wait()
{ {
if ( ShouldWait() ) wxMutexList::Node *ownmutexnode = ShouldWait();
if ( ownmutexnode )
{ {
if ( pthread_cond_wait( &m_condition, &m_mutex ) != 0 ) if ( pthread_cond_wait( &m_condition, ownmutexnode->GetData() ) != 0 )
{ {
// not supposed to ever happen // not supposed to ever happen
wxFAIL_MSG( _T("pthread_cond_wait() failed") ); wxFAIL_MSG( _T("pthread_cond_wait() failed") );
} }
}
WaitDone(); WaitDone(ownmutexnode);
}
} }
bool wxConditionInternal::WaitWithTimeout(const timespec* ts) bool wxConditionInternal::WaitWithTimeout(const timespec* ts)
{ {
bool ok; bool ok;
if ( ShouldWait() ) wxMutexList::Node *ownmutexnode = ShouldWait();
if ( ownmutexnode )
{ {
switch ( pthread_cond_timedwait( &m_condition, &m_mutex, ts ) ) switch ( pthread_cond_timedwait( &m_condition, ownmutexnode->GetData(), ts ) )
{ {
case 0: case 0:
// condition signaled // condition signaled
@@ -411,6 +436,7 @@ bool wxConditionInternal::WaitWithTimeout(const timespec* ts)
// wait interrupted or timeout elapsed // wait interrupted or timeout elapsed
ok = FALSE; ok = FALSE;
} }
WaitDone(ownmutexnode);
} }
else else
{ {
@@ -418,36 +444,65 @@ bool wxConditionInternal::WaitWithTimeout(const timespec* ts)
ok = TRUE; ok = TRUE;
} }
WaitDone();
return ok; return ok;
} }
void wxConditionInternal::LockAllMutexes()
{
wxMutexList::Node *mutexnode = m_mutexes.GetFirst();
while ( mutexnode )
{
pthread_mutex_lock(mutexnode->GetData());
mutexnode = mutexnode->GetNext();
}
}
void wxConditionInternal::UnlockAllMutexes()
{
wxMutexList::Node *mutexnode = m_mutexes.GetFirst();
while ( mutexnode )
{
pthread_mutex_unlock(mutexnode->GetData());
mutexnode = mutexnode->GetNext();
}
}
void wxConditionInternal::Signal() void wxConditionInternal::Signal()
{ {
// calls to HasWaiters() must be serialized
MutexLock lock(m_mutexProtect);
if ( HasWaiters() ) if ( HasWaiters() )
{ {
MutexLock lock(m_mutex); // wait
LockAllMutexes();
if ( pthread_cond_signal( &m_condition ) != 0 ) if ( pthread_cond_signal( &m_condition ) != 0 )
{ {
// shouldn't ever happen // shouldn't ever happen
wxFAIL_MSG(_T("pthread_cond_signal() failed")); wxFAIL_MSG(_T("pthread_cond_signal() failed"));
} }
UnlockAllMutexes();
} }
} }
void wxConditionInternal::Broadcast() void wxConditionInternal::Broadcast()
{ {
MutexLock lock(m_mutexProtect);
if ( HasWaiters() ) if ( HasWaiters() )
{ {
MutexLock lock(m_mutex); LockAllMutexes();
if ( pthread_cond_broadcast( &m_condition ) != 0 ) if ( pthread_cond_broadcast( &m_condition ) != 0 )
{ {
// shouldn't ever happen // shouldn't ever happen
wxFAIL_MSG(_T("pthread_cond_broadcast() failed")); wxFAIL_MSG(_T("pthread_cond_broadcast() failed"));
} }
UnlockAllMutexes();
} }
} }
@@ -763,13 +818,10 @@ void wxThreadInternal::Wait()
wxMutexGuiLeave(); wxMutexGuiLeave();
bool isDetached = m_isDetached; bool isDetached = m_isDetached;
#ifdef __VMS wxThreadIdType id = GetId();
long long id = (long long)GetId();
#else wxLogTrace(TRACE_THREADS,
long id = (long)GetId(); _T("Starting to wait for thread %ld to exit."), id);
#endif
wxLogTrace(TRACE_THREADS, _T("Starting to wait for thread %ld to exit."),
id);
// wait until the thread terminates (we're blocking in _another_ thread, // wait until the thread terminates (we're blocking in _another_ thread,
// of course) // of course)
@@ -1142,15 +1194,9 @@ unsigned int wxThread::GetPriority() const
return m_internal->GetPriority(); return m_internal->GetPriority();
} }
#ifdef __VMS wxThreadIdType wxThread::GetId() const
unsigned long long wxThread::GetId() const
{ {
return (unsigned long long)m_internal->GetId(); return m_internal->GetId();
#else
unsigned long wxThread::GetId() const
{
return (unsigned long)m_internal->GetId();
#endif
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------