X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2Fmoof%2Fthread.hh;h=af251e157b8a64ef433c70794ddde72509c8a98f;hp=1e710d8c0e66ef81e913a0a072d0646fa29099a0;hb=44b3014bce798789e795242d1556cb7449e6386a;hpb=af88821a172c4dfd138b91b2a5148ae50b502fa2 diff --git a/src/moof/thread.hh b/src/moof/thread.hh index 1e710d8..af251e1 100644 --- a/src/moof/thread.hh +++ b/src/moof/thread.hh @@ -1,34 +1,36 @@ -/*] Copyright (c) 2009-2010, Charles McGarvey [************************** +/*] Copyright (c) 2009-2011, Charles McGarvey [***************************** **] All rights reserved. * -* vi:ts=4 sw=4 tw=75 -* * Distributable under the terms and conditions of the 2-clause BSD license; * see the file COPYING for a complete text of the license. * -**************************************************************************/ +*****************************************************************************/ #ifndef _MOOF_THREAD_HH_ #define _MOOF_THREAD_HH_ -/** - * \file thread.hh - * Light C++ wrapper around the SDL threads API. - */ - -#include "config.h" - #include #include +#include #include #include +#include +/** + * \file thread.hh + * Light C++ wrapper around the SDL threads API. + */ + namespace moof { +// forward declarations +class runloop; +typedef boost::shared_ptr runloop_ptr; + /** * Represents a thread which may be running. You cannot instantiate a * thread object directly; new threads are created by detaching functions @@ -40,29 +42,27 @@ class thread { public: - typedef boost::function function; - + typedef boost::function function; /** * Construct an invalid thread object which has no association with any * real thread. */ - thread() : - thread_(0) {} + thread(); /** * Execute a function in a new thread. * \param function The function to execute. * \return The new thread, or an invalid thread if an error occurred. */ - static thread detach(const function& function) - { - thread::function* fcopy = new thread::function(function); - SDL_Thread* thread = SDL_CreateThread(&thread::run, (void*)fcopy); - if (thread == 0) delete fcopy; - return moof::thread(thread); - } + static thread detach(const function& function); + /** + * Detach a new thread and run its runloop with an initial timer. + * \param timer The timer to schedule on the thread. + * \return The new thread, or an invalid thread if an error occurred. + */ + static thread detach(timer& timer); /** * Wait for the thread to terminate, getting its return value. The @@ -71,21 +71,21 @@ public: */ int wait() { - int i; - SDL_WaitThread(thread_, &i); - thread_ = 0; - return i; + if (thread_) + { + int i; + SDL_WaitThread(thread_, &i); + thread_ = 0; + return i; + } + return 1; } /** * Forcefully kill the thread without giving it a chance to clean up * after itself. The thread will be invalidated. Don't use this. */ - void kill() - { - SDL_KillThread(thread_); - thread_ = 0; - } + void kill(); /** * Get whether or not the thread object is associated with a real @@ -97,7 +97,6 @@ public: return thread_ != 0; } - /** * Get a unique identifier for this thread, if it is valid. * \return The identifier. @@ -116,21 +115,26 @@ public: return SDL_ThreadID(); } + /** + * Get the thread's runloop. + * \return The thread's runloop. + */ + moof::runloop& runloop() const; -private: - - thread(SDL_Thread* thread) : - thread_(thread) {} + /** + * Get the runloop for the main thread. + * \return The runloop. + */ + static moof::runloop& main_runloop(); - static int run(void* arg) - { - int code = (*(function*)arg)(); - delete (function*)arg; - return code; - } +private: + static void spawn(thread* thread); + static int run(void* arg); - SDL_Thread* thread_; + function function_; + SDL_Thread* thread_; + runloop_ptr runloop_; }; @@ -165,6 +169,7 @@ public: virtual int wait() = 0; }; + /** * An asynchronous task that is run to be executed in a separated thread. */ @@ -176,7 +181,10 @@ public: * Get the thread object the task is executing in. * \return The thread. */ - const class thread& thread() const { return thread_; } + const class thread& thread() const + { + return thread_; + } /** * Block the current thread until the task thread is finished. @@ -187,7 +195,6 @@ public: return thread_.wait(); } - protected: class thread thread_; @@ -205,27 +212,26 @@ public: /** * Construct a mutex. */ - mutex() : + mutex() : mutex_(SDL_CreateMutex()) {} /** * Deconstruct a mutex. */ - ~mutex() + ~mutex() { SDL_DestroyMutex(mutex_); } - /** * Block until the calling thread can secure exclusive access to the * code protected by the mutex. * \return True if the lock was acquired, false otherwise. * \see lock */ - bool acquire_lock() + bool acquire_lock() { - return (SDL_LockMutex(mutex_) == 0); + return SDL_LockMutex(mutex_) == 0; } /** @@ -234,48 +240,46 @@ public: * \return True if the mutex was unlocked, false otherwise. * \see lock */ - bool release_lock() + bool release_lock() { - return (SDL_UnlockMutex(mutex_) == 0); + return SDL_UnlockMutex(mutex_) == 0; } - /** * As an alternative method for locking, objects of this class will * automagically release the lock if it is still locked at * deconstruction. Therefore, it's generally safer to use this method * since it makes it much more difficult to forget to unlock a mutex. */ - class lock - { - public: + class lock + { + public: /** * Construct a lock. * \param mutex The mutex. */ - explicit lock(mutex& mutex, bool lock = true) : + explicit lock(mutex& mutex, bool lock = true) : mutex_(mutex), is_locked_(false) { - if (lock) if (!acquire()) throw "mutex lock not acquired"; + if (lock && !acquire()) throw "mutex lock not acquired"; } /** * Deconstruct a lock. The lock is automagically released if it is * still locked. */ - ~lock() + ~lock() { if (is_locked_) release(); } - /** * Try to acquire a lock on the mutex. * \return True if the mutex was locked, false otherwise. */ - bool acquire() + bool acquire() { return (is_locked_ = mutex_.acquire_lock()); } @@ -284,32 +288,29 @@ public: * Release the lock. * \return True if the mutex was unlocked, false otherwise. */ - bool release() + bool release() { bool result = mutex_.release_lock(); is_locked_ = false; return result; } - /** * Get whether or not the mutex is locked. * \return True if the mutex is locked, false otherwise. */ - bool is_locked() const + bool is_locked() const { return is_locked_; } + protected: - protected: - - mutex& mutex_; - bool is_locked_; - - friend class condition; - }; + mutex& mutex_; + bool is_locked_; + friend class condition; + }; private: @@ -329,7 +330,7 @@ public: /** * Construct a condition. */ - condition() + condition() { condition_ = SDL_CreateCond(); } @@ -337,12 +338,11 @@ public: /** * Deconstruct a condition. */ - ~condition() + ~condition() { SDL_DestroyCond(condition_); } - /** * Unlock the mutex and wait for another thread to notify the thread, * at which point the mutex will be re-locked and the method will @@ -352,7 +352,7 @@ public: */ bool wait(mutex& mutex) { - return (SDL_CondWait(condition_, mutex.mutex_) == 0); + return SDL_CondWait(condition_, mutex.mutex_) == 0; } /** @@ -362,10 +362,10 @@ public: * \param lock The lock. * \return True if the thread was notified, false otherwise. */ - bool wait(mutex::lock& lock) + bool wait(mutex::lock& lock) { - return (SDL_CondWait(condition_, lock.mutex_.mutex_) == 0); - } + return SDL_CondWait(condition_, lock.mutex_.mutex_) == 0; + } /** * Unlock the mutex and wait for another thread to notify the thread, @@ -376,10 +376,10 @@ public: * \param timeout Number of seconds to wait. * \return True if the thread was notified, false otherwise. */ - bool wait(mutex& mutex, scalar timeout) + bool wait(mutex& mutex, scalar timeout) { Uint32 ms = timeout * SCALAR(1000.0); - return (SDL_CondWaitTimeout(condition_, mutex.mutex_, ms) == 0); + return SDL_CondWaitTimeout(condition_, mutex.mutex_, ms) == 0; } /** @@ -391,33 +391,31 @@ public: * \param timeout Number of seconds to wait. * \return True if the thread was notified, false otherwise. */ - bool wait(mutex::lock& lock, scalar timeout) + bool wait(mutex::lock& lock, scalar timeout) { Uint32 ms = timeout * SCALAR(1000.0); - return (SDL_CondWaitTimeout(condition_, - lock.mutex_.mutex_, ms) == 0); + return SDL_CondWaitTimeout(condition_, + lock.mutex_.mutex_, ms) == 0; } - /** * Notify one other thread that is waiting on the condition. * \return True on success, false otherwise. */ - bool notify() + bool notify() { - return (SDL_CondSignal(condition_) == 0); + return SDL_CondSignal(condition_) == 0; } /** * Notify all other threads that are waiting on the condition. * \return True on success, false otherwise. */ - bool notify_all() + bool notify_all() { - return (SDL_CondBroadcast(condition_) == 0); + return SDL_CondBroadcast(condition_) == 0; } - private: SDL_cond* condition_; @@ -435,7 +433,7 @@ public: * Construct a semaphore. * \param value The initial value of the semaphore. */ - explicit semaphore(uint32_t value) + explicit semaphore(uint32_t value) { semaphore_ = SDL_CreateSemaphore(value); } @@ -443,21 +441,20 @@ public: /** * Deconstruct a semaphore. */ - ~semaphore() + ~semaphore() { SDL_DestroySemaphore(semaphore_); } - /** * Block until the calling thread can secure exclusive access to the * code protected by the semaphore. * \return True if the lock was acquired, false otherwise. * \see lock */ - bool acquire_lock() + bool acquire_lock() { - return (SDL_SemWait(semaphore_) == 0); + return SDL_SemWait(semaphore_) == 0; } /** @@ -469,7 +466,7 @@ public: bool acquire_lock(scalar timeout) { Uint32 ms = timeout * SCALAR(1000.0); - return (SDL_SemWaitTimeout(semaphore_, ms) == 0); + return SDL_SemWaitTimeout(semaphore_, ms) == 0; } /** @@ -478,9 +475,9 @@ public: * \return True if the semaphore was unlocked, false otherwise. * \see lock */ - bool release_lock() + bool release_lock() { - return (SDL_SemPost(semaphore_) == 0); + return SDL_SemPost(semaphore_) == 0; } /** @@ -488,9 +485,9 @@ public: * immediately available. * \return True if the semaphore was locked, false otherwise. */ - bool try_lock() + bool try_lock() { - return (SDL_SemTryWait(semaphore_) == 0); + return SDL_SemTryWait(semaphore_) == 0; } /** @@ -500,36 +497,35 @@ public: * since it makes it much more difficult to forget to unlock a * semaphore. */ - class lock - { - public: + class lock + { + public: /** * Construct a lock. * \param semaphore The semaphore. */ - explicit lock(semaphore& semaphore, bool lock = true) : + explicit lock(semaphore& semaphore, bool lock = true) : semaphore_(semaphore), is_locked_(false) { - if (lock) if (!acquire()) throw "semaphore lock not acquired"; + if (lock && !acquire()) throw "semaphore lock not acquired"; } /** * Deconstruct a lock. The lock is automagically released if it is * still locked. */ - ~lock() + ~lock() { if (is_locked_) release(); } - /** * Try to acquire a lock on the semaphore. * \return True if the semaphore was locked, false otherwise. */ - bool acquire() + bool acquire() { return (is_locked_ = semaphore_.acquire_lock()); } @@ -538,7 +534,7 @@ public: * Release the lock. * \return True if the semaphore was unlocked, false otherwise. */ - bool release() + bool release() { bool result = semaphore_.release_lock(); is_locked_ = false; @@ -549,18 +545,16 @@ public: * Get whether or not the semaphore is locked. * \return True if the semaphore is locked, false otherwise. */ - bool is_locked() const + bool is_locked() const { return is_locked_; } - - - protected: - semaphore& semaphore_; - bool is_locked_; - }; + protected: + semaphore& semaphore_; + bool is_locked_; + }; private: @@ -569,9 +563,9 @@ private: #if ENABLE_THREADS -#define MOOF_DECLARE_MUTEX(M) moof::mutex M +#define MOOF_DECLARE_MUTEX(M) moof::mutex M #define MOOF_DECLARE_STATIC_MUTEX(M) static moof::mutex M -#define MOOF_MUTEX_LOCK(M) moof::mutex::lock lock_##M(M) +#define MOOF_MUTEX_LOCK(M) moof::mutex::lock lock_##M(M) #else #define MOOF_DECLARE_MUTEX(M) #define MOOF_DECLARE_STATIC_MUTEX(M)