]> git.mxchange.org Git - simgear.git/blob - simgear/threads/SGThread.hxx
MINGW patch from BenoƮt Laniel
[simgear.git] / simgear / threads / SGThread.hxx
1 // SGThread - Simple pthread class wrappers.
2 //
3 // Written by Bernie Bright, started April 2001.
4 //
5 // Copyright (C) 2001  Bernard Bright - bbright@bigpond.net.au
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //
21 // $Id$
22
23 #ifndef SGTHREAD_HXX_INCLUDED
24 #define SGTHREAD_HXX_INCLUDED 1
25
26 #include <simgear/compiler.h>
27
28 #include <pthread.h>
29 #include <cassert>
30 #include <cerrno>
31
32 class SGThread;
33
34 extern "C" {
35     void* start_handler( void* );
36 };
37
38 /**
39  * Encapsulate generic threading methods.
40  * Users derive a class from SGThread and implement the run() member function.
41  */
42 class SGThread
43 {
44 public:
45     /**
46      * SGThread cancelation modes.
47      */
48     enum cancel_t
49     {
50         CANCEL_DISABLE = 0,
51         CANCEL_DEFERRED,
52         CANCEL_IMMEDIATE
53     };
54 public:
55
56     /**
57      * Create a new thread object.
58      * When a SGThread object is created it does not begin execution
59      * immediately.  It is started by calling the start() member function.
60      */
61     SGThread();
62
63     /**
64      * Start the underlying thread of execution.
65      * @param cpu An optional parameter to specify on which CPU to run this
66      * thread (only supported on IRIX at this time).
67      * @return Pthread error code if execution fails, otherwise returns 0.
68      */
69     int start( unsigned cpu = 0 );
70
71     /**
72      * Sends a cancellation request to the underlying thread.  The target
73      * thread will either ignore the request, honor it immediately or defer
74      * it until it reaches a cancellation point.
75      */
76     void cancel();
77
78     /**
79      * Suspends the exection of the calling thread until this thread
80      * terminates.
81      */
82     void join();
83
84 protected:
85     /**
86      * Destroy a thread object.
87      * This is protected so that its illegal to simply delete a thread
88      * - it must return from its run() function.
89      */
90     virtual ~SGThread();
91
92     /**
93      * Set the threads cancellation mode.
94      * @param mode The required cancellation mode.
95      */
96     void set_cancel( cancel_t mode );
97
98     /**
99      * All threads execute by deriving the run() method of SGThread.
100      * If this function terminates then the thread also terminates.
101      */
102     virtual void run() = 0;
103
104 private:
105
106     /**
107      * Pthread thread identifier.
108      */
109     pthread_t tid;
110
111     friend void* start_handler( void* );
112
113 private:
114     // Disable copying.
115     SGThread( const SGThread& );
116     SGThread& operator=( const SGThread& );
117 };
118
119 inline
120 SGThread::SGThread()
121 {
122 }
123
124 inline
125 SGThread::~SGThread()
126 {
127 }
128
129 inline int
130 SGThread::start( unsigned cpu )
131 {
132     int status = pthread_create( &tid, 0, start_handler, this );
133     assert( status == 0 );
134     (void)status;
135 #if defined( sgi )
136     if ( !status && !cpu )
137         pthread_setrunon_np( cpu );
138 #endif
139     return status;
140 }
141
142 inline void
143 SGThread::join()
144 {
145     int status = pthread_join( tid, 0 );
146     assert( status == 0 );
147     (void)status;
148 }
149
150 inline void
151 SGThread::cancel()
152 {
153     int status = pthread_cancel( tid );
154     assert( status == 0 );
155     (void)status;
156 }
157
158 /**
159  * A mutex is used to protect a section of code such that at any time
160  * only a single thread can execute the code.
161  */
162 class SGMutex
163 {
164     friend class SGPthreadCond;
165
166 public:
167
168     /**
169      * Create a new mutex.
170      * Under Linux this is a 'fast' mutex.
171      */
172     SGMutex();
173
174     /**
175      * Destroy a mutex object.
176      * Note: it is the responsibility of the caller to ensure the mutex is
177      * unlocked before destruction occurs.
178      */
179     ~SGMutex();
180
181     /**
182      * Lock this mutex.
183      * If the mutex is currently unlocked, it becomes locked and owned by
184      * the calling thread.  If the mutex is already locked by another thread,
185      * the calling thread is suspended until the mutex is unlocked.  If the
186      * mutex is already locked and owned by the calling thread, the calling
187      * thread is suspended until the mutex is unlocked, effectively causing
188      * the calling thread to deadlock.
189      *
190      * @see SGMutex::trylock
191      */
192     void lock();
193
194     /**
195      * Try to lock the mutex for the current thread.  Behaves like lock except
196      * that it doesn't block the calling thread.
197      * @return true if mutex was successfully locked, otherwise false.
198      * @see SGMutex::lock
199      */
200     bool trylock();
201
202     /**
203      * Unlock this mutex.
204      * It is assumed that the mutex is locked and owned by the calling thread.
205      */
206     void unlock();
207
208 protected:
209
210     /**
211      * Pthread mutex.
212      */
213     pthread_mutex_t mutex;
214 };
215
216 inline SGMutex::SGMutex()
217 {
218     int status = pthread_mutex_init( &mutex, 0 );
219     assert( status == 0 );
220     (void)status;
221 }
222
223 inline SGMutex::~SGMutex()
224 {
225     int status = pthread_mutex_destroy( &mutex );
226     assert( status == 0 );
227     (void)status;
228 }
229
230 inline void SGMutex::lock()
231 {
232     int status = pthread_mutex_lock( &mutex );
233     assert( status == 0 );
234     (void)status;
235 }
236
237 inline void SGMutex::unlock()
238 {
239     int status = pthread_mutex_unlock( &mutex );
240     assert( status == 0 );
241     (void)status;
242 }
243
244 /**
245  * A condition variable is a synchronization device that allows threads to 
246  * suspend execution until some predicate on shared data is satisfied.
247  * A condition variable is always associated with a mutex to avoid race
248  * conditions. 
249  */
250 class SGPthreadCond
251 {
252 public:
253     /**
254      * Create a new condition variable.
255      */
256     SGPthreadCond();
257
258     /**
259      * Destroy the condition object.
260      */
261     ~SGPthreadCond();
262
263     /**
264      * Wait for this condition variable to be signaled.
265      *
266      * @param SGMutex& reference to a locked mutex.
267      */
268     void wait( SGMutex& );
269
270     /**
271      * Wait for this condition variable to be signaled for at most
272      * 'ms' milliseconds.
273      *
274      * @param mutex reference to a locked mutex.
275      * @param ms milliseconds to wait for a signal.
276      *
277      * @return 
278      */
279     bool wait( SGMutex& mutex, unsigned long ms );
280
281     /**
282      * Wake one thread waiting on this condition variable.
283      * Nothing happens if no threads are waiting.
284      * If several threads are waiting exactly one thread is restarted.  It
285      * is not specified which.
286      */
287     void signal();
288
289     /**
290      * Wake all threads waiting on this condition variable.
291      * Nothing happens if no threads are waiting.
292      */
293     void broadcast();
294
295 private:
296     // Disable copying.
297     SGPthreadCond(const SGPthreadCond& );
298     SGPthreadCond& operator=(const SGPthreadCond& );
299
300 private:
301
302     /**
303      * The Pthread conditon variable.
304      */
305     pthread_cond_t cond;
306 };
307
308 inline SGPthreadCond::SGPthreadCond()
309 {
310     int status = pthread_cond_init( &cond, 0 );
311     assert( status == 0 );
312     (void)status;
313 }
314
315 inline SGPthreadCond::~SGPthreadCond()
316 {
317     int status = pthread_cond_destroy( &cond );
318     assert( status == 0 );
319     (void)status;
320 }
321
322 inline void SGPthreadCond::signal()
323 {
324     int status = pthread_cond_signal( &cond );
325     assert( status == 0 );
326     (void)status;
327 }
328
329 inline void SGPthreadCond::broadcast()
330 {
331     int status = pthread_cond_broadcast( &cond );
332     assert( status == 0 );
333     (void)status;
334 }
335
336 inline void SGPthreadCond::wait( SGMutex& mutex )
337 {
338     int status = pthread_cond_wait( &cond, &mutex.mutex );
339     assert( status == 0 );
340     (void)status;
341 }
342
343 #endif /* SGTHREAD_HXX_INCLUDED */