]> git.mxchange.org Git - simgear.git/blob - simgear/threads/SGThread.hxx
Patch from Julian Foad:
[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      * @return Pthread error code if execution fails, otherwise returns 0.
71      */
72     int start();
73
74     /**
75      * Sends a cancellation request to the underlying thread.  The target
76      * thread will either ignore the request, honor it immediately or defer
77      * it until it reaches a cancellation point.
78      */
79     void cancel();
80
81     /**
82      * Suspends the exection of the calling thread until this thread
83      * terminates.
84      */
85     void join();
86
87 protected:
88     /**
89      * Destroy a thread object.
90      * This is protected so that its illegal to simply delete a thread
91      * - it must return from its run() function.
92      */
93     virtual ~SGThread();
94
95     /**
96      * Set the threads cancellation mode.
97      * @param mode The required cancellation mode.
98      */
99     void set_cancel( cancel_t mode );
100
101     /**
102      * All threads execute by deriving the run() method of SGThread.
103      * If this function terminates then the thread also terminates.
104      */
105     virtual void run() = 0;
106
107 private:
108
109     /**
110      * Pthread thread identifier.
111      */
112     pthread_t tid;
113
114     friend void* start_handler( void* );
115
116 private:
117     // Disable copying.
118     SGThread( const SGThread& );
119     SGThread& operator=( const SGThread& );
120 };
121
122 inline
123 SGThread::SGThread()
124 {
125 }
126
127 inline
128 SGThread::~SGThread()
129 {
130 }
131
132 inline int
133 SGThread::start()
134 {
135     int status = pthread_create( &tid, 0, start_handler, this );
136     assert( status == 0 );
137     return status;
138 }
139
140 inline void
141 SGThread::join()
142 {
143     int status = pthread_join( tid, 0 );
144     assert( status == 0 );
145 }
146
147 inline void
148 SGThread::cancel()
149 {
150     int status = pthread_cancel( tid );
151     assert( status == 0 );
152 }
153
154 /**
155  * A mutex is used to protect a section of code such that at any time
156  * only a single thread can execute the code.
157  */
158 class SGMutex
159 {
160     friend class SGCondition;
161
162 public:
163
164     /**
165      * Create a new mutex.
166      * Under Linux this is a 'fast' mutex.
167      */
168     SGMutex();
169
170     /**
171      * Destroy a mutex object.
172      * Note: it is the responsibility of the caller to ensure the mutex is
173      * unlocked before destruction occurs.
174      */
175     ~SGMutex();
176
177     /**
178      * Lock this mutex.
179      * If the mutex is currently unlocked, it becomes locked and owned by
180      * the calling thread.  If the mutex is already locked by another thread,
181      * the calling thread is suspended until the mutex is unlocked.  If the
182      * mutex is already locked and owned by the calling thread, the calling
183      * thread is suspended until the mutex is unlocked, effectively causing
184      * the calling thread to deadlock.
185      *
186      * @see SGMutex::trylock
187      */
188     void lock();
189
190     /**
191      * Try to lock the mutex for the current thread.  Behaves like lock except
192      * that it doesn't block the calling thread.
193      * @return true if mutex was successfully locked, otherwise false.
194      * @see SGMutex::lock
195      */
196     bool trylock();
197
198     /**
199      * Unlock this mutex.
200      * It is assumed that the mutex is locked and owned by the calling thread.
201      */
202     void unlock();
203
204 protected:
205
206     /**
207      * Pthread mutex.
208      */
209     pthread_mutex_t mutex;
210 };
211
212 inline SGMutex::SGMutex()
213 {
214     int status = pthread_mutex_init( &mutex, 0 );
215     assert( status == 0 );
216 }
217
218 inline SGMutex::~SGMutex()
219 {
220     int status = pthread_mutex_destroy( &mutex );
221     assert( status == 0 );
222 }
223
224 inline void SGMutex::lock()
225 {
226     int status = pthread_mutex_lock( &mutex );
227     assert( status == 0 );
228 }
229
230 inline void SGMutex::unlock()
231 {
232     int status = pthread_mutex_unlock( &mutex );
233     assert( status == 0 );
234 }
235
236 /**
237  * A condition variable is a synchronization device that allows threads to 
238  * suspend execution until some predicate on shared data is satisfied.
239  * A condition variable is always associated with a mutex to avoid race
240  * conditions. 
241  */
242 class SGCondition
243 {
244 public:
245     /**
246      * Create a new condition variable.
247      */
248     SGCondition();
249
250     /**
251      * Destroy the condition object.
252      */
253     ~SGCondition();
254
255     /**
256      * Wait for this condition variable to be signaled.
257      *
258      * @param SGMutex& reference to a locked mutex.
259      */
260     void wait( SGMutex& );
261
262     /**
263      * Wait for this condition variable to be signaled for at most
264      * 'ms' milliseconds.
265      *
266      * @param mutex reference to a locked mutex.
267      * @param ms milliseconds to wait for a signal.
268      *
269      * @return 
270      */
271     bool wait( SGMutex& mutex, unsigned long ms );
272
273     /**
274      * Wake one thread waiting on this condition variable.
275      * Nothing happens if no threads are waiting.
276      * If several threads are waiting exactly one thread is restarted.  It
277      * is not specified which.
278      */
279     void signal();
280
281     /**
282      * Wake all threads waiting on this condition variable.
283      * Nothing happens if no threads are waiting.
284      */
285     void broadcast();
286
287 private:
288     // Disable copying.
289     SGCondition(const SGCondition& );
290     SGCondition& operator=(const SGCondition& );
291
292 private:
293
294     /**
295      * The Pthread conditon variable.
296      */
297     pthread_cond_t cond;
298 };
299
300 inline SGCondition::SGCondition()
301 {
302     int status = pthread_cond_init( &cond, 0 );
303     assert( status == 0 );
304 }
305
306 inline SGCondition::~SGCondition()
307 {
308     int status = pthread_cond_destroy( &cond );
309     assert( status == 0 );
310 }
311
312 inline void SGCondition::signal()
313 {
314     int status = pthread_cond_signal( &cond );
315     assert( status == 0 );
316 }
317
318 inline void SGCondition::broadcast()
319 {
320     int status = pthread_cond_broadcast( &cond );
321     assert( status == 0 );
322 }
323
324 inline void SGCondition::wait( SGMutex& mutex )
325 {
326     int status = pthread_cond_wait( &cond, &mutex.mutex );
327     assert( status == 0 );
328 }
329
330 #endif /* SGTHREAD_HXX_INCLUDED */