]>
Dogcows Code - chaz/yoink/blob - src/moof/thread.hh
17d3170beaf4ce1304feb2da5584332a19d2250c
2 /*] Copyright (c) 2009-2011, Charles McGarvey [*****************************
3 **] All rights reserved.
5 * Distributable under the terms and conditions of the 2-clause BSD license;
6 * see the file COPYING for a complete text of the license.
8 *****************************************************************************/
10 #ifndef _MOOF_THREAD_HH_
11 #define _MOOF_THREAD_HH_
15 * Light C++ wrapper around the SDL threads API.
18 #include <boost/bind.hpp>
19 #include <boost/function.hpp>
20 #include <boost/shared_ptr.hpp>
23 #include <moof/math.hh>
24 #include <moof/timer.hh>
30 // forward declarations
32 typedef boost::shared_ptr
<runloop
> runloop_ptr
;
35 * Represents a thread which may be running. You cannot instantiate a
36 * thread object directly; new threads are created by detaching functions
37 * using the detach() method. Once a thread is detached, it will continue
38 * running until the function returns. You don't need to keep the thread
39 * object you want to wait() or kill() the thread later.
45 typedef boost::function
<int(thread
&)> function
;
48 * Construct an invalid thread object which has no association with any
54 * Execute a function in a new thread.
55 * \param function The function to execute.
56 * \return The new thread, or an invalid thread if an error occurred.
58 static thread
detach(const function
& function
);
61 * Detach a new thread and run its runloop with an initial timer.
62 * \param timer The timer to schedule on the thread.
63 * \return The new thread, or an invalid thread if an error occurred.
65 static thread
detach(timer
& timer
);
68 * Wait for the thread to terminate, getting its return value. The
69 * thread will be invalidated.
70 * \return The integer value returned by the detached function.
77 SDL_WaitThread(thread_
, &i
);
85 * Forcefully kill the thread without giving it a chance to clean up
86 * after itself. The thread will be invalidated. Don't use this.
91 * Get whether or not the thread object is associated with a real
93 * \return True if the thread is valid, false otherwise.
101 * Get a unique identifier for this thread, if it is valid.
102 * \return The identifier.
104 uint32_t identifier() const
106 return SDL_GetThreadID(thread_
);
110 * Get the unique identifier of the calling thread.
111 * \return The identifier.
113 static uint32_t current_identifier()
115 return SDL_ThreadID();
119 * Get the thread's runloop.
120 * \return The thread's runloop.
122 moof::runloop
& runloop() const;
125 * Get the runloop for the main thread.
126 * \return The runloop.
128 static moof::runloop
& main_runloop();
132 static void spawn(thread
* thread
);
133 static int run(void* arg
);
137 runloop_ptr runloop_
;
142 * An abstract class representing some task that is to be run
150 * Deconstruct the task.
152 virtual ~async_task() {}
155 * Get whether or not the task is done.
156 * \return True if the task is done, false otherwise.
158 virtual bool is_done() const = 0;
163 virtual void run() = 0;
166 * Block the current thread until the task is finished.
167 * \return A value representing the state of the finished task.
169 virtual int wait() = 0;
174 * An asynchronous task that is run to be executed in a separated thread.
181 * Get the thread object the task is executing in.
182 * \return The thread.
184 const class thread
& thread() const
190 * Block the current thread until the task thread is finished.
191 * \return The integer value returned by the task function.
195 return thread_
.wait();
200 class thread thread_
;
205 * A mutex to protect sensitive sections of code from threads which might
206 * otherwise cause unpredictable results.
216 mutex_(SDL_CreateMutex()) {}
219 * Deconstruct a mutex.
223 SDL_DestroyMutex(mutex_
);
227 * Block until the calling thread can secure exclusive access to the
228 * code protected by the mutex.
229 * \return True if the lock was acquired, false otherwise.
234 return SDL_LockMutex(mutex_
) == 0;
238 * Unlock the mutex. Call this after the sensitive block of code to
239 * allow another thread to acquire the lock.
240 * \return True if the mutex was unlocked, false otherwise.
245 return SDL_UnlockMutex(mutex_
) == 0;
249 * As an alternative method for locking, objects of this class will
250 * automagically release the lock if it is still locked at
251 * deconstruction. Therefore, it's generally safer to use this method
252 * since it makes it much more difficult to forget to unlock a mutex.
260 * \param mutex The mutex.
262 explicit lock(mutex
& mutex
, bool lock
= true) :
266 if (lock
&& !acquire()) throw "mutex lock not acquired";
270 * Deconstruct a lock. The lock is automagically released if it is
275 if (is_locked_
) release();
279 * Try to acquire a lock on the mutex.
280 * \return True if the mutex was locked, false otherwise.
284 return (is_locked_
= mutex_
.acquire_lock());
289 * \return True if the mutex was unlocked, false otherwise.
293 bool result
= mutex_
.release_lock();
299 * Get whether or not the mutex is locked.
300 * \return True if the mutex is locked, false otherwise.
302 bool is_locked() const
312 friend class condition
;
319 friend class condition
;
324 * A class representing a condition variable.
331 * Construct a condition.
335 condition_
= SDL_CreateCond();
339 * Deconstruct a condition.
343 SDL_DestroyCond(condition_
);
347 * Unlock the mutex and wait for another thread to notify the thread,
348 * at which point the mutex will be re-locked and the method will
350 * \param mutex The mutex.
351 * \return True if the thread was notified, false otherwise.
353 bool wait(mutex
& mutex
)
355 return SDL_CondWait(condition_
, mutex
.mutex_
) == 0;
359 * Unlock the mutex associated with a lock and wait for another thread
360 * to notify the thread, at which point the lock will be re-locked and
361 * the method will return.
362 * \param lock The lock.
363 * \return True if the thread was notified, false otherwise.
365 bool wait(mutex::lock
& lock
)
367 return SDL_CondWait(condition_
, lock
.mutex_
.mutex_
) == 0;
371 * Unlock the mutex and wait for another thread to notify the thread,
372 * at which point the mutex will be re-locked and the method will
373 * return. If the thread was not notified before a certain number of
374 * seconds, the method will return anyway.
375 * \param mutex The mutex.
376 * \param timeout Number of seconds to wait.
377 * \return True if the thread was notified, false otherwise.
379 bool wait(mutex
& mutex
, scalar timeout
)
381 Uint32 ms
= timeout
* SCALAR(1000.0);
382 return SDL_CondWaitTimeout(condition_
, mutex
.mutex_
, ms
) == 0;
386 * Unlock the mutex associated with a lock and wait for another thread
387 * to notify the thread, at which point the lock will be re-locked and
388 * the method will return. If the thread was not notified before a
389 * certain number of seconds, the method will return anyway.
390 * \param lock The lock.
391 * \param timeout Number of seconds to wait.
392 * \return True if the thread was notified, false otherwise.
394 bool wait(mutex::lock
& lock
, scalar timeout
)
396 Uint32 ms
= timeout
* SCALAR(1000.0);
397 return SDL_CondWaitTimeout(condition_
,
398 lock
.mutex_
.mutex_
, ms
) == 0;
402 * Notify one other thread that is waiting on the condition.
403 * \return True on success, false otherwise.
407 return SDL_CondSignal(condition_
) == 0;
411 * Notify all other threads that are waiting on the condition.
412 * \return True on success, false otherwise.
416 return SDL_CondBroadcast(condition_
) == 0;
421 SDL_cond
* condition_
;
433 * Construct a semaphore.
434 * \param value The initial value of the semaphore.
436 explicit semaphore(uint32_t value
)
438 semaphore_
= SDL_CreateSemaphore(value
);
442 * Deconstruct a semaphore.
446 SDL_DestroySemaphore(semaphore_
);
450 * Block until the calling thread can secure exclusive access to the
451 * code protected by the semaphore.
452 * \return True if the lock was acquired, false otherwise.
457 return SDL_SemWait(semaphore_
) == 0;
461 * Block until the calling thread can secure exclusive access to the
462 * code protected by the semaphore, or until the timeout expires.
463 * \param timeout Number of seconds to try.
464 * \return True if the lock was acquired, false otherwise.
466 bool acquire_lock(scalar timeout
)
468 Uint32 ms
= timeout
* SCALAR(1000.0);
469 return SDL_SemWaitTimeout(semaphore_
, ms
) == 0;
473 * Unlock the semaphore. Call this after the sensitive block of code
474 * to allow another thread to acquire the lock.
475 * \return True if the semaphore was unlocked, false otherwise.
480 return SDL_SemPost(semaphore_
) == 0;
484 * Try to lock the semaphore, but don't block if the lock is not
485 * immediately available.
486 * \return True if the semaphore was locked, false otherwise.
490 return SDL_SemTryWait(semaphore_
) == 0;
494 * As an alternative method for locking, objects of this class will
495 * automagically release the lock if it is still locked at
496 * deconstruction. Therefore, it's generally safer to use this method
497 * since it makes it much more difficult to forget to unlock a
506 * \param semaphore The semaphore.
508 explicit lock(semaphore
& semaphore
, bool lock
= true) :
509 semaphore_(semaphore
),
512 if (lock
&& !acquire()) throw "semaphore lock not acquired";
516 * Deconstruct a lock. The lock is automagically released if it is
521 if (is_locked_
) release();
525 * Try to acquire a lock on the semaphore.
526 * \return True if the semaphore was locked, false otherwise.
530 return (is_locked_
= semaphore_
.acquire_lock());
535 * \return True if the semaphore was unlocked, false otherwise.
539 bool result
= semaphore_
.release_lock();
545 * Get whether or not the semaphore is locked.
546 * \return True if the semaphore is locked, false otherwise.
548 bool is_locked() const
555 semaphore
& semaphore_
;
566 #define MOOF_DECLARE_MUTEX(M) moof::mutex M
567 #define MOOF_DECLARE_STATIC_MUTEX(M) static moof::mutex M
568 #define MOOF_MUTEX_LOCK(M) moof::mutex::lock lock_##M(M)
570 #define MOOF_DECLARE_MUTEX(M)
571 #define MOOF_DECLARE_STATIC_MUTEX(M)
572 #define MOOF_MUTEX_LOCK(M)
578 #endif // _MOOF_THREAD_HH_
This page took 0.06372 seconds and 3 git commands to generate.