]> git.mxchange.org Git - simgear.git/blob - simgear/threads/SGThread.hxx
69b10b8b501922155b7b483e9c8d7b775ed52792
[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., 675 Mass Ave, Cambridge, MA 02139, 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 #if defined ( SG_HAVE_STD_INCLUDES )
30 #  include <cassert>
31 #  include <cerrno>
32 #else
33 #  include <assert.h>
34 #  include <sys/errno.h>
35 #endif
36
37 class SGThread;
38
39 extern "C" {
40     void* start_handler( void* );
41 };
42
43 /**
44  * Encapsulate generic threading methods.
45  * Users derive a class from SGThread and implement the run() member function.
46  */
47 class SGThread
48 {
49 public:
50     /**
51      * SGThread cancelation modes.
52      */
53     enum cancel_t
54     {
55         CANCEL_DISABLE = 0,
56         CANCEL_DEFERRED,
57         CANCEL_IMMEDIATE
58     };
59 public:
60
61     /**
62      * Create a new thread object.
63      * When a SGThread object is created it does not begin execution
64      * immediately.  It is started by calling the start() member function.
65      */
66     SGThread();
67
68     /**
69      * Start the underlying thread of execution.
70      * @param cpu An optional parameter to specify on which CPU to run this
71      * thread (only supported on IRIX at this time).
72      * @return Pthread error code if execution fails, otherwise returns 0.
73      */
74     int start( unsigned cpu = 0 );
75
76     /**
77      * Sends a cancellation request to the underlying thread.  The target
78      * thread will either ignore the request, honor it immediately or defer
79      * it until it reaches a cancellation point.
80      */
81     void cancel();
82
83     /**
84      * Suspends the exection of the calling thread until this thread
85      * terminates.
86      */
87     void join();
88
89 protected:
90     /**
91      * Destroy a thread object.
92      * This is protected so that its illegal to simply delete a thread
93      * - it must return from its run() function.
94      */
95     virtual ~SGThread();
96
97     /**
98      * Set the threads cancellation mode.
99      * @param mode The required cancellation mode.
100      */
101     void set_cancel( cancel_t mode );
102
103     /**
104      * All threads execute by deriving the run() method of SGThread.
105      * If this function terminates then the thread also terminates.
106      */
107     virtual void run() = 0;
108
109 private:
110
111     /**
112      * Pthread thread identifier.
113      */
114     pthread_t tid;
115
116     friend void* start_handler( void* );
117
118 private:
119     // Disable copying.
120     SGThread( const SGThread& );
121     SGThread& operator=( const SGThread& );
122 };
123
124 inline
125 SGThread::SGThread()
126 {
127 }
128
129 inline
130 SGThread::~SGThread()
131 {
132 }
133
134 inline int
135 SGThread::start( unsigned cpu )
136 {
137     pthread_attr_t attr;
138     pthread_attr_init(&attr);
139     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
140           
141     int status = pthread_create( &tid, &attr, start_handler, this );
142     assert( status == 0 );
143     pthread_attr_destroy(&attr);
144 #if defined( sgi )
145     if ( !status && !cpu )
146         pthread_setrunon_np( cpu );
147 #endif
148     return status;
149 }
150
151 inline void
152 SGThread::join()
153 {
154     int status = pthread_join( tid, 0 );
155     assert( status == 0 );
156 }
157
158 inline void
159 SGThread::cancel()
160 {
161     int status = pthread_cancel( tid );
162     assert( status == 0 );
163 }
164
165 /**
166  * A mutex is used to protect a section of code such that at any time
167  * only a single thread can execute the code.
168  */
169 class SGMutex
170 {
171     friend class SGPthreadCond;
172
173 public:
174
175     /**
176      * Create a new mutex.
177      * Under Linux this is a 'fast' mutex.
178      */
179     SGMutex();
180
181     /**
182      * Destroy a mutex object.
183      * Note: it is the responsibility of the caller to ensure the mutex is
184      * unlocked before destruction occurs.
185      */
186     ~SGMutex();
187
188     /**
189      * Lock this mutex.
190      * If the mutex is currently unlocked, it becomes locked and owned by
191      * the calling thread.  If the mutex is already locked by another thread,
192      * the calling thread is suspended until the mutex is unlocked.  If the
193      * mutex is already locked and owned by the calling thread, the calling
194      * thread is suspended until the mutex is unlocked, effectively causing
195      * the calling thread to deadlock.
196      *
197      * @see SGMutex::trylock
198      */
199     void lock();
200
201     /**
202      * Try to lock the mutex for the current thread.  Behaves like lock except
203      * that it doesn't block the calling thread.
204      * @return true if mutex was successfully locked, otherwise false.
205      * @see SGMutex::lock
206      */
207     bool trylock();
208
209     /**
210      * Unlock this mutex.
211      * It is assumed that the mutex is locked and owned by the calling thread.
212      */
213     void unlock();
214
215 protected:
216
217     /**
218      * Pthread mutex.
219      */
220     pthread_mutex_t mutex;
221 };
222
223 inline SGMutex::SGMutex()
224 {
225 #if 0
226     // Note: This will only work if the mutex is in shared memory,
227     // something we don't support enyhow. -EMH-
228     pthread_mutexattr_t mutex_attr = 0;
229     pthread_mutexattr_init(&mutex_attr);
230     pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);
231     int status = pthread_mutex_init( &mutex, &mutex_attr );
232     assert( status == 0 );
233     pthread_mutexattr_destroy(&mutex_attr);
234 #else
235     int status = pthread_mutex_init( &mutex, 0 );
236     assert( status == 0 );
237 #endif
238 }
239
240 inline SGMutex::~SGMutex()
241 {
242     int status = pthread_mutex_destroy( &mutex );
243     assert( status == 0 );
244 }
245
246 inline void SGMutex::lock()
247 {
248     int status = pthread_mutex_lock( &mutex );
249     assert( status == 0 );
250 }
251
252 inline void SGMutex::unlock()
253 {
254     int status = pthread_mutex_unlock( &mutex );
255     assert( status == 0 );
256 }
257
258 /**
259  * A condition variable is a synchronization device that allows threads to 
260  * suspend execution until some predicate on shared data is satisfied.
261  * A condition variable is always associated with a mutex to avoid race
262  * conditions. 
263  */
264 class SGPthreadCond
265 {
266 public:
267     /**
268      * Create a new condition variable.
269      */
270     SGPthreadCond();
271
272     /**
273      * Destroy the condition object.
274      */
275     ~SGPthreadCond();
276
277     /**
278      * Wait for this condition variable to be signaled.
279      *
280      * @param SGMutex& reference to a locked mutex.
281      */
282     void wait( SGMutex& );
283
284     /**
285      * Wait for this condition variable to be signaled for at most
286      * 'ms' milliseconds.
287      *
288      * @param mutex reference to a locked mutex.
289      * @param ms milliseconds to wait for a signal.
290      *
291      * @return 
292      */
293     bool wait( SGMutex& mutex, unsigned long ms );
294
295     /**
296      * Wake one thread waiting on this condition variable.
297      * Nothing happens if no threads are waiting.
298      * If several threads are waiting exactly one thread is restarted.  It
299      * is not specified which.
300      */
301     void signal();
302
303     /**
304      * Wake all threads waiting on this condition variable.
305      * Nothing happens if no threads are waiting.
306      */
307     void broadcast();
308
309 private:
310     // Disable copying.
311     SGPthreadCond(const SGPthreadCond& );
312     SGPthreadCond& operator=(const SGPthreadCond& );
313
314 private:
315
316     /**
317      * The Pthread conditon variable.
318      */
319     pthread_cond_t cond;
320 };
321
322 inline SGPthreadCond::SGPthreadCond()
323 {
324     int status = pthread_cond_init( &cond, 0 );
325     assert( status == 0 );
326 }
327
328 inline SGPthreadCond::~SGPthreadCond()
329 {
330     int status = pthread_cond_destroy( &cond );
331     assert( status == 0 );
332 }
333
334 inline void SGPthreadCond::signal()
335 {
336     int status = pthread_cond_signal( &cond );
337     assert( status == 0 );
338 }
339
340 inline void SGPthreadCond::broadcast()
341 {
342     int status = pthread_cond_broadcast( &cond );
343     assert( status == 0 );
344 }
345
346 inline void SGPthreadCond::wait( SGMutex& mutex )
347 {
348     int status = pthread_cond_wait( &cond, &mutex.mutex );
349     assert( status == 0 );
350 }
351
352 #endif /* SGTHREAD_HXX_INCLUDED */