1 /////////////////////////////////////////////////////////////////////////////
2 // Name: include/wx/thrimpl.cpp
3 // Purpose: common part of wxThread Implementations
4 // Author: Vadim Zeitlin
6 // Created: 04.06.02 (extracted from src/*/thread.cpp files)
8 // Copyright: (c) Vadim Zeitlin (2002)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // this file is supposed to be included only by the various thread.cpp
14 // ----------------------------------------------------------------------------
16 // ----------------------------------------------------------------------------
18 wxMutex::wxMutex(wxMutexType mutexType
)
20 m_internal
= new wxMutexInternal(mutexType
);
22 if ( !m_internal
->IsOk() )
34 bool wxMutex::IsOk() const
36 return m_internal
!= NULL
;
39 wxMutexError
wxMutex::Lock()
41 wxCHECK_MSG( m_internal
, wxMUTEX_INVALID
,
42 _T("wxMutex::Lock(): not initialized") );
44 return m_internal
->Lock();
47 wxMutexError
wxMutex::LockTimeout(unsigned long ms
)
49 wxCHECK_MSG( m_internal
, wxMUTEX_INVALID
,
50 _T("wxMutex::Lock(): not initialized") );
52 return m_internal
->Lock(ms
);
55 wxMutexError
wxMutex::TryLock()
57 wxCHECK_MSG( m_internal
, wxMUTEX_INVALID
,
58 _T("wxMutex::TryLock(): not initialized") );
60 return m_internal
->TryLock();
63 wxMutexError
wxMutex::Unlock()
65 wxCHECK_MSG( m_internal
, wxMUTEX_INVALID
,
66 _T("wxMutex::Unlock(): not initialized") );
68 return m_internal
->Unlock();
71 // --------------------------------------------------------------------------
72 // wxConditionInternal
73 // --------------------------------------------------------------------------
75 // Win32 and OS/2 don't have explicit support for the POSIX condition
76 // variables and their events/event semaphores have quite different semantics,
77 // so we reimplement the conditions from scratch using the mutexes and
79 #if defined(__WXMSW__) || defined(__OS2__) || defined(__EMX__)
81 class wxConditionInternal
84 wxConditionInternal(wxMutex
& mutex
);
86 bool IsOk() const { return m_mutex
.IsOk() && m_semaphore
.IsOk(); }
89 wxCondError
WaitTimeout(unsigned long milliseconds
);
92 wxCondError
Broadcast();
95 // the number of threads currently waiting for this condition
98 // the critical section protecting m_numWaiters
99 wxCriticalSection m_csWaiters
;
102 wxSemaphore m_semaphore
;
104 DECLARE_NO_COPY_CLASS(wxConditionInternal
)
107 wxConditionInternal::wxConditionInternal(wxMutex
& mutex
)
110 // another thread can't access it until we return from ctor, so no need to
111 // protect access to m_numWaiters here
115 wxCondError
wxConditionInternal::Wait()
117 // increment the number of waiters
119 wxCriticalSectionLocker
lock(m_csWaiters
);
125 // a potential race condition can occur here
127 // after a thread increments m_numWaiters, and unlocks the mutex and before
128 // the semaphore.Wait() is called, if another thread can cause a signal to
131 // this race condition is handled by using a semaphore and incrementing the
132 // semaphore only if m_numWaiters is greater that zero since the semaphore,
133 // can 'remember' signals the race condition will not occur
135 // wait ( if necessary ) and decrement semaphore
136 wxSemaError err
= m_semaphore
.Wait();
139 if ( err
== wxSEMA_NO_ERROR
)
140 return wxCOND_NO_ERROR
;
141 else if ( err
== wxSEMA_TIMEOUT
)
142 return wxCOND_TIMEOUT
;
144 return wxCOND_MISC_ERROR
;
147 wxCondError
wxConditionInternal::WaitTimeout(unsigned long milliseconds
)
150 wxCriticalSectionLocker
lock(m_csWaiters
);
156 // a race condition can occur at this point in the code
158 // please see the comments in Wait(), for details
160 wxSemaError err
= m_semaphore
.WaitTimeout(milliseconds
);
162 if ( err
== wxSEMA_TIMEOUT
)
164 // another potential race condition exists here it is caused when a
165 // 'waiting' thread times out, and returns from WaitForSingleObject,
166 // but has not yet decremented m_numWaiters
168 // at this point if another thread calls signal() then the semaphore
169 // will be incremented, but the waiting thread will miss it.
171 // to handle this particular case, the waiting thread calls
172 // WaitForSingleObject again with a timeout of 0, after locking
173 // m_csWaiters. This call does not block because of the zero
174 // timeout, but will allow the waiting thread to catch the missed
176 wxCriticalSectionLocker
lock(m_csWaiters
);
178 wxSemaError err2
= m_semaphore
.WaitTimeout(0);
180 if ( err2
!= wxSEMA_NO_ERROR
)
188 return err
== wxSEMA_NO_ERROR
? wxCOND_NO_ERROR
189 : err
== wxSEMA_TIMEOUT
? wxCOND_TIMEOUT
193 wxCondError
wxConditionInternal::Signal()
195 wxCriticalSectionLocker
lock(m_csWaiters
);
197 if ( m_numWaiters
> 0 )
199 // increment the semaphore by 1
200 if ( m_semaphore
.Post() != wxSEMA_NO_ERROR
)
201 return wxCOND_MISC_ERROR
;
206 return wxCOND_NO_ERROR
;
209 wxCondError
wxConditionInternal::Broadcast()
211 wxCriticalSectionLocker
lock(m_csWaiters
);
213 while ( m_numWaiters
> 0 )
215 if ( m_semaphore
.Post() != wxSEMA_NO_ERROR
)
216 return wxCOND_MISC_ERROR
;
221 return wxCOND_NO_ERROR
;
226 // ----------------------------------------------------------------------------
228 // ----------------------------------------------------------------------------
230 wxCondition::wxCondition(wxMutex
& mutex
)
232 m_internal
= new wxConditionInternal(mutex
);
234 if ( !m_internal
->IsOk() )
241 wxCondition::~wxCondition()
246 bool wxCondition::IsOk() const
248 return m_internal
!= NULL
;
251 wxCondError
wxCondition::Wait()
253 wxCHECK_MSG( m_internal
, wxCOND_INVALID
,
254 _T("wxCondition::Wait(): not initialized") );
256 return m_internal
->Wait();
259 wxCondError
wxCondition::WaitTimeout(unsigned long milliseconds
)
261 wxCHECK_MSG( m_internal
, wxCOND_INVALID
,
262 _T("wxCondition::Wait(): not initialized") );
264 return m_internal
->WaitTimeout(milliseconds
);
267 wxCondError
wxCondition::Signal()
269 wxCHECK_MSG( m_internal
, wxCOND_INVALID
,
270 _T("wxCondition::Signal(): not initialized") );
272 return m_internal
->Signal();
275 wxCondError
wxCondition::Broadcast()
277 wxCHECK_MSG( m_internal
, wxCOND_INVALID
,
278 _T("wxCondition::Broadcast(): not initialized") );
280 return m_internal
->Broadcast();
283 // --------------------------------------------------------------------------
285 // --------------------------------------------------------------------------
287 wxSemaphore::wxSemaphore(int initialcount
, int maxcount
)
289 m_internal
= new wxSemaphoreInternal( initialcount
, maxcount
);
290 if ( !m_internal
->IsOk() )
297 wxSemaphore::~wxSemaphore()
302 bool wxSemaphore::IsOk() const
304 return m_internal
!= NULL
;
307 wxSemaError
wxSemaphore::Wait()
309 wxCHECK_MSG( m_internal
, wxSEMA_INVALID
,
310 _T("wxSemaphore::Wait(): not initialized") );
312 return m_internal
->Wait();
315 wxSemaError
wxSemaphore::TryWait()
317 wxCHECK_MSG( m_internal
, wxSEMA_INVALID
,
318 _T("wxSemaphore::TryWait(): not initialized") );
320 return m_internal
->TryWait();
323 wxSemaError
wxSemaphore::WaitTimeout(unsigned long milliseconds
)
325 wxCHECK_MSG( m_internal
, wxSEMA_INVALID
,
326 _T("wxSemaphore::WaitTimeout(): not initialized") );
328 return m_internal
->WaitTimeout(milliseconds
);
331 wxSemaError
wxSemaphore::Post()
333 wxCHECK_MSG( m_internal
, wxSEMA_INVALID
,
334 _T("wxSemaphore::Post(): not initialized") );
336 return m_internal
->Post();
339 // ----------------------------------------------------------------------------
341 // ----------------------------------------------------------------------------
343 #include "wx/utils.h"
345 void wxThread::Sleep(unsigned long milliseconds
)
347 wxMilliSleep(milliseconds
);