+++ /dev/null
-
-/*] Copyright (c) 2009-2010, 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.
-*
-**************************************************************************/
-
-/**
- * \file Thread.hh
- * Light C++ wrapper around the SDL threads API.
- */
-
-#ifndef _MOOF_THREAD_HH_
-#define _MOOF_THREAD_HH_
-
-#include <boost/bind.hpp>
-#include <boost/function.hpp>
-#include <SDL/SDL.h>
-
-#include <Moof/Math.hh>
-
-
-namespace Mf {
-
-
-/**
- * Represents a thread which may be running. You cannot instantiate a
- * thread object directly; new threads are created by detaching functions
- * using the detach() method. Once a thread is detached, it will continue
- * running until the function returns. You don't need to keep the thread
- * object you want to wait() or kill() the thread later.
- */
-class Thread
-{
-public:
-
- typedef boost::function<int(void)> Function;
-
-
- /**
- * Construct an invalid thread object which has no association with any
- * real thread.
- */
- Thread() :
- mThread(0) {}
-
- /**
- * 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)
- {
- Function* fcopy = new Function(function);
- SDL_Thread* thread = SDL_CreateThread(&Thread::run, (void*)fcopy);
- if (thread == 0) delete fcopy;
- return Thread(thread);
- }
-
-
- /**
- * Wait for the thread to terminate, getting its return value. The
- * thread will be invalidated.
- * \return The integer value returned by the detached function.
- */
- int wait()
- {
- int i;
- SDL_WaitThread(mThread, &i);
- mThread = 0;
- return i;
- }
-
- /**
- * 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(mThread);
- mThread = 0;
- }
-
- /**
- * Get whether or not the thread object is associated with a real
- * thread.
- * \return True if the thread is valid, false otherwise.
- */
- bool isValid() const
- {
- return mThread != 0;
- }
-
-
- /**
- * Get a unique identifier for this thread, if it is valid.
- * \return The identifier.
- */
- uint32_t identifier() const
- {
- return SDL_GetThreadID(mThread);
- }
-
- /**
- * Get the unique identifier of the calling thread.
- * \return The identifier.
- */
- static uint32_t currentIdentifier()
- {
- return SDL_ThreadID();
- }
-
-
-private:
-
- Thread(SDL_Thread* thread) :
- mThread(thread) {}
-
- static int run(void* arg)
- {
- int code = (*(Function*)arg)();
- delete (Function*)arg;
- return code;
- }
-
-
- SDL_Thread* mThread;
-};
-
-
-/**
- * An abstract class representing some task that is to be run
- * asynchronously.
- */
-class AsyncTask
-{
-public:
-
- /**
- * Deconstruct the task.
- */
- virtual ~AsyncTask() {}
-
- /**
- * Get whether or not the task is done.
- * \return True if the task is done, false otherwise.
- */
- virtual bool isDone() const = 0;
-
- /**
- * Begin the task.
- */
- virtual void run() = 0;
-
- /**
- * Block the current thread until the task is finished.
- * \return A value representing the state of the finished task.
- */
- virtual int wait() = 0;
-};
-
-/**
- * An asynchronous task that is run to be executed in a separated thread.
- */
-class ThreadedTask
-{
-public:
-
- /**
- * Get the thread object the task is executing in.
- * \return The thread.
- */
- const Thread& thread() const { return mThread; }
-
- /**
- * Block the current thread until the task thread is finished.
- * \return The integer value returned by the task function.
- */
- int wait()
- {
- return mThread.wait();
- }
-
-
-protected:
-
- Thread mThread;
-};
-
-
-/**
- * A mutex to protect sensitive sections of code from threads which might
- * otherwise cause unpredictable results.
- */
-class Mutex
-{
-public:
-
- /**
- * Construct a mutex.
- */
- Mutex() :
- mMutex(SDL_CreateMutex()) {}
-
- /**
- * Deconstruct a mutex.
- */
- ~Mutex()
- {
- SDL_DestroyMutex(mMutex);
- }
-
-
- /**
- * 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 acquireLock()
- {
- return (SDL_LockMutex(mMutex) == 0);
- }
-
- /**
- * Unlock the mutex. Call this after the sensitive block of code to
- * allow another thread to acquire the lock.
- * \return True if the mutex was unlocked, false otherwise.
- * \see Lock
- */
- bool releaseLock()
- {
- return (SDL_UnlockMutex(mMutex) == 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:
-
- /**
- * Construct a lock.
- * \param mutex The mutex.
- */
- explicit Lock(Mutex& mutex) :
- mMutex(mutex),
- mIsLocked(false) {}
-
- /**
- * Deconstruct a lock. The lock is automagically released if it is
- * still locked.
- */
- ~Lock()
- {
- if (mIsLocked) release();
- }
-
-
- /**
- * Try to acquire a lock on the mutex.
- * \return True if the mutex was locked, false otherwise.
- */
- bool acquire()
- {
- return (mIsLocked = mMutex.acquireLock());
- }
-
- /**
- * Release the lock.
- * \return True if the mutex was unlocked, false otherwise.
- */
- bool release()
- {
- bool result = mMutex.releaseLock();
- mIsLocked = false;
- return result;
- }
-
-
- /**
- * Get whether or not the mutex is locked.
- * \return True if the mutex is locked, false otherwise.
- */
- bool isLocked() const
- {
- return mIsLocked;
- }
-
-
- protected:
-
- Mutex& mMutex;
- bool mIsLocked;
-
- friend class Condition;
- };
-
- /**
- * This type of lock tries to acquire a lock on the mutex during
- * construction and releases the lock on deconstruction.
- */
- class ScopedLock : private Lock
- {
- public:
-
- /**
- * Construct a lock.
- * \param mutex The mutex.
- */
- explicit ScopedLock(Mutex& mutex) :
- Lock(mutex)
- {
- acquire();
- }
-
- /**
- * Get whether or not the mutex is locked.
- * \return True if the mutex is locked, false otherwise.
- */
- bool isLocked() const
- {
- return Lock::isLocked();
- }
- };
-
-
-private:
-
- SDL_mutex* mMutex;
-
- friend class Condition;
-};
-
-
-/**
- * A class representing a condition variable.
- */
-class Condition
-{
-public:
-
- /**
- * Construct a condition.
- */
- Condition()
- {
- mCondition = SDL_CreateCond();
- }
-
- /**
- * Deconstruct a condition.
- */
- ~Condition()
- {
- SDL_DestroyCond(mCondition);
- }
-
-
- /**
- * 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
- * return.
- * \param mutex The mutex.
- * \return True if the thread was notified, false otherwise.
- */
- bool wait(Mutex& mutex)
- {
- return (SDL_CondWait(mCondition, mutex.mMutex) == 0);
- }
-
- /**
- * Unlock the mutex associated with a lock and wait for another thread
- * to notify the thread, at which point the lock will be re-locked and
- * the method will return.
- * \param lock The lock.
- * \return True if the thread was notified, false otherwise.
- */
- bool wait(Mutex::Lock& lock)
- {
- return (SDL_CondWait(mCondition, lock.mMutex.mMutex) == 0);
- }
-
- /**
- * 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
- * return. If the thread was not notified before a certain number of
- * seconds, the method will return anyway.
- * \param mutex The mutex.
- * \param timeout Number of seconds to wait.
- * \return True if the thread was notified, false otherwise.
- */
- bool wait(Mutex& mutex, Scalar timeout)
- {
- Uint32 ms = timeout * SCALAR(1000.0);
- return (SDL_CondWaitTimeout(mCondition, mutex.mMutex, ms) == 0);
- }
-
- /**
- * Unlock the mutex associated with a lock and wait for another thread
- * to notify the thread, at which point the lock will be re-locked and
- * the method will return. If the thread was not notified before a
- * certain number of seconds, the method will return anyway.
- * \param lock The lock.
- * \param timeout Number of seconds to wait.
- * \return True if the thread was notified, false otherwise.
- */
- bool wait(Mutex::Lock& lock, Scalar timeout)
- {
- Uint32 ms = timeout * SCALAR(1000.0);
- return (SDL_CondWaitTimeout(mCondition,
- lock.mMutex.mMutex, ms) == 0);
- }
-
-
- /**
- * Notify one other thread that is waiting on the condition.
- * \return True on success, false otherwise.
- */
- bool notify()
- {
- return (SDL_CondSignal(mCondition) == 0);
- }
-
- /**
- * Notify all other threads that are waiting on the condition.
- * \return True on success, false otherwise.
- */
- bool notifyAll()
- {
- return (SDL_CondBroadcast(mCondition) == 0);
- }
-
-
-private:
-
- SDL_cond* mCondition;
-};
-
-
-/**
- * A semaphore class.
- */
-class Semaphore
-{
-public:
-
- /**
- * Construct a semaphore.
- * \param value The initial value of the semaphore.
- */
- explicit Semaphore(uint32_t value)
- {
- mSemaphore = SDL_CreateSemaphore(value);
- }
-
- /**
- * Deconstruct a semaphore.
- */
- ~Semaphore()
- {
- SDL_DestroySemaphore(mSemaphore);
- }
-
-
- /**
- * 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 acquireLock()
- {
- return (SDL_SemWait(mSemaphore) == 0);
- }
-
- /**
- * Block until the calling thread can secure exclusive access to the
- * code protected by the semaphore, or until the timeout expires.
- * \param timeout Number of seconds to try.
- * \return True if the lock was acquired, false otherwise.
- */
- bool acquireLock(Scalar timeout)
- {
- Uint32 ms = timeout * SCALAR(1000.0);
- return (SDL_SemWaitTimeout(mSemaphore, ms) == 0);
- }
-
- /**
- * Unlock the semaphore. Call this after the sensitive block of code
- * to allow another thread to acquire the lock.
- * \return True if the semaphore was unlocked, false otherwise.
- * \see Lock
- */
- bool releaseLock()
- {
- return (SDL_SemPost(mSemaphore) == 0);
- }
-
- /**
- * Try to lock the semaphore, but don't block if the lock is not
- * immediately available.
- * \return True if the semaphore was locked, false otherwise.
- */
- bool tryLock()
- {
- return (SDL_SemTryWait(mSemaphore) == 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
- * semaphore.
- */
- class Lock
- {
- public:
-
- /**
- * Construct a lock.
- * \param semaphore The semaphore.
- */
- explicit Lock(Semaphore& semaphore) :
- mSemaphore(semaphore),
- mIsLocked(false) {}
-
- /**
- * Deconstruct a lock. The lock is automagically released if it is
- * still locked.
- */
- ~Lock()
- {
- if (mIsLocked) release();
- }
-
-
- /**
- * Try to acquire a lock on the semaphore.
- * \return True if the semaphore was locked, false otherwise.
- */
- bool acquire()
- {
- return (mIsLocked = mSemaphore.acquireLock());
- }
-
- /**
- * Release the lock.
- * \return True if the semaphore was unlocked, false otherwise.
- */
- bool release()
- {
- bool result = mSemaphore.releaseLock();
- mIsLocked = false;
- return result;
- }
-
- /**
- * Get whether or not the semaphore is locked.
- * \return True if the semaphore is locked, false otherwise.
- */
- bool isLocked() const
- {
- return mIsLocked;
- }
-
-
- protected:
-
- Semaphore& mSemaphore;
- bool mIsLocked;
- };
-
- /**
- * This type of lock tries to acquire a lock on the semaphore during
- * construction and releases the lock on deconstruction.
- */
- class ScopedLock : private Lock
- {
- public:
-
- /**
- * Construct a lock.
- * \param semaphore The semaphore.
- */
- explicit ScopedLock(Semaphore& semaphore) :
- Lock(semaphore)
- {
- acquire();
- }
-
- /**
- * Get whether or not the semaphore is locked.
- * \return True if the semaphore is locked, false otherwise.
- */
- bool isLocked() const
- {
- return Lock::isLocked();
- }
- };
-
-
-private:
-
- SDL_sem* mSemaphore;
-};
-
-
-} // namespace Mf
-
-#endif // _MOOF_THREAD_HH_
-