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 wxT("wxMutex::Lock(): not initialized") );
44 return m_internal
->Lock();
47 wxMutexError
wxMutex::LockTimeout(unsigned long ms
)
49 wxCHECK_MSG( m_internal
, wxMUTEX_INVALID
,
50 wxT("wxMutex::Lock(): not initialized") );
52 return m_internal
->Lock(ms
);
55 wxMutexError
wxMutex::TryLock()
57 wxCHECK_MSG( m_internal
, wxMUTEX_INVALID
,
58 wxT("wxMutex::TryLock(): not initialized") );
60 return m_internal
->TryLock();
63 wxMutexError
wxMutex::Unlock()
65 wxCHECK_MSG( m_internal
, wxMUTEX_INVALID
,
66 wxT("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 wxDECLARE_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 // after unlocking the mutex other threads may Signal() us, but it is ok
126 // now as we had already incremented m_numWaiters so Signal() will post the
127 // semaphore and decrement m_numWaiters back even if it is called before we
129 const wxSemaError err
= m_semaphore
.Wait();
133 if ( err
== wxSEMA_NO_ERROR
)
135 // m_numWaiters was decremented by Signal()
136 return wxCOND_NO_ERROR
;
139 // but in case of an error we need to do it manually
141 wxCriticalSectionLocker
lock(m_csWaiters
);
145 return err
== wxSEMA_TIMEOUT
? wxCOND_TIMEOUT
: wxCOND_MISC_ERROR
;
148 wxCondError
wxConditionInternal::WaitTimeout(unsigned long milliseconds
)
151 wxCriticalSectionLocker
lock(m_csWaiters
);
157 wxSemaError err
= m_semaphore
.WaitTimeout(milliseconds
);
161 if ( err
== wxSEMA_NO_ERROR
)
162 return wxCOND_NO_ERROR
;
164 if ( err
== wxSEMA_TIMEOUT
)
166 // a potential race condition exists here: it happens when a waiting
167 // thread times out but doesn't have time to decrement m_numWaiters yet
168 // before Signal() is called in another thread
170 // to handle this particular case, check the semaphore again after
171 // acquiring m_csWaiters lock -- this will catch the signals missed
172 // during this window
173 wxCriticalSectionLocker
lock(m_csWaiters
);
175 err
= m_semaphore
.WaitTimeout(0);
176 if ( err
== wxSEMA_NO_ERROR
)
177 return wxCOND_NO_ERROR
;
179 // we need to decrement m_numWaiters ourselves as it wasn't done by
183 return err
== wxSEMA_TIMEOUT
? wxCOND_TIMEOUT
: wxCOND_MISC_ERROR
;
186 // undo m_numWaiters++ above in case of an error
188 wxCriticalSectionLocker
lock(m_csWaiters
);
192 return wxCOND_MISC_ERROR
;
195 wxCondError
wxConditionInternal::Signal()
197 wxCriticalSectionLocker
lock(m_csWaiters
);
199 if ( m_numWaiters
> 0 )
201 // increment the semaphore by 1
202 if ( m_semaphore
.Post() != wxSEMA_NO_ERROR
)
203 return wxCOND_MISC_ERROR
;
208 return wxCOND_NO_ERROR
;
211 wxCondError
wxConditionInternal::Broadcast()
213 wxCriticalSectionLocker
lock(m_csWaiters
);
215 while ( m_numWaiters
> 0 )
217 if ( m_semaphore
.Post() != wxSEMA_NO_ERROR
)
218 return wxCOND_MISC_ERROR
;
223 return wxCOND_NO_ERROR
;
228 // ----------------------------------------------------------------------------
230 // ----------------------------------------------------------------------------
232 wxCondition::wxCondition(wxMutex
& mutex
)
234 m_internal
= new wxConditionInternal(mutex
);
236 if ( !m_internal
->IsOk() )
243 wxCondition::~wxCondition()
248 bool wxCondition::IsOk() const
250 return m_internal
!= NULL
;
253 wxCondError
wxCondition::Wait()
255 wxCHECK_MSG( m_internal
, wxCOND_INVALID
,
256 wxT("wxCondition::Wait(): not initialized") );
258 return m_internal
->Wait();
261 wxCondError
wxCondition::WaitTimeout(unsigned long milliseconds
)
263 wxCHECK_MSG( m_internal
, wxCOND_INVALID
,
264 wxT("wxCondition::Wait(): not initialized") );
266 return m_internal
->WaitTimeout(milliseconds
);
269 wxCondError
wxCondition::Signal()
271 wxCHECK_MSG( m_internal
, wxCOND_INVALID
,
272 wxT("wxCondition::Signal(): not initialized") );
274 return m_internal
->Signal();
277 wxCondError
wxCondition::Broadcast()
279 wxCHECK_MSG( m_internal
, wxCOND_INVALID
,
280 wxT("wxCondition::Broadcast(): not initialized") );
282 return m_internal
->Broadcast();
285 // --------------------------------------------------------------------------
287 // --------------------------------------------------------------------------
289 wxSemaphore::wxSemaphore(int initialcount
, int maxcount
)
291 m_internal
= new wxSemaphoreInternal( initialcount
, maxcount
);
292 if ( !m_internal
->IsOk() )
299 wxSemaphore::~wxSemaphore()
304 bool wxSemaphore::IsOk() const
306 return m_internal
!= NULL
;
309 wxSemaError
wxSemaphore::Wait()
311 wxCHECK_MSG( m_internal
, wxSEMA_INVALID
,
312 wxT("wxSemaphore::Wait(): not initialized") );
314 return m_internal
->Wait();
317 wxSemaError
wxSemaphore::TryWait()
319 wxCHECK_MSG( m_internal
, wxSEMA_INVALID
,
320 wxT("wxSemaphore::TryWait(): not initialized") );
322 return m_internal
->TryWait();
325 wxSemaError
wxSemaphore::WaitTimeout(unsigned long milliseconds
)
327 wxCHECK_MSG( m_internal
, wxSEMA_INVALID
,
328 wxT("wxSemaphore::WaitTimeout(): not initialized") );
330 return m_internal
->WaitTimeout(milliseconds
);
333 wxSemaError
wxSemaphore::Post()
335 wxCHECK_MSG( m_internal
, wxSEMA_INVALID
,
336 wxT("wxSemaphore::Post(): not initialized") );
338 return m_internal
->Post();
341 // ----------------------------------------------------------------------------
343 // ----------------------------------------------------------------------------
345 #include "wx/utils.h"
347 void wxThread::Sleep(unsigned long milliseconds
)
349 wxMilliSleep(milliseconds
);