-/*] 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 <boost/bind.hpp>
#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
#include <SDL/SDL.h>
#include <moof/math.hh>
+#include <moof/timer.hh>
+/**
+ * \file thread.hh
+ * Light C++ wrapper around the SDL threads API.
+ */
+
namespace moof {
+// forward declarations
+class runloop;
+typedef boost::shared_ptr<runloop> runloop_ptr;
+
/**
* Represents a thread which may be running. You cannot instantiate a
* thread object directly; new threads are created by detaching functions
{
public:
- typedef boost::function<int(void)> function;
-
+ typedef boost::function<int(thread&)> 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
*/
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
return thread_ != 0;
}
-
/**
* Get a unique identifier for this thread, if it is valid.
* \return The identifier.
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_;
};
virtual int wait() = 0;
};
+
/**
* An asynchronous task that is run to be executed in a separated thread.
*/
* 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.
return thread_.wait();
}
-
protected:
class thread thread_;
/**
* 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;
}
/**
* \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());
}
* 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:
/**
* Construct a condition.
*/
- condition()
+ condition()
{
condition_ = SDL_CreateCond();
}
/**
* 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
*/
bool wait(mutex& mutex)
{
- return (SDL_CondWait(condition_, mutex.mutex_) == 0);
+ return SDL_CondWait(condition_, mutex.mutex_) == 0;
}
/**
* \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,
* \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;
}
/**
* \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_;
* 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);
}
/**
* 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;
}
/**
bool acquire_lock(scalar timeout)
{
Uint32 ms = timeout * SCALAR(1000.0);
- return (SDL_SemWaitTimeout(semaphore_, ms) == 0);
+ return SDL_SemWaitTimeout(semaphore_, ms) == 0;
}
/**
* \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;
}
/**
* 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;
}
/**
* 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());
}
* Release the lock.
* \return True if the semaphore was unlocked, false otherwise.
*/
- bool release()
+ bool release()
{
bool result = semaphore_.release_lock();
is_locked_ = false;
* 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:
#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)