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