]>
Dogcows Code - chaz/yoink/blob - src/moof/thread.hh
2 /*] Copyright (c) 2009-2010, Charles McGarvey [**************************
3 **] All rights reserved.
7 * Distributable under the terms and conditions of the 2-clause BSD license;
8 * see the file COPYING for a complete text of the license.
10 **************************************************************************/
12 #ifndef _MOOF_THREAD_HH_
13 #define _MOOF_THREAD_HH_
17 * Light C++ wrapper around the SDL threads API.
20 #include <boost/bind.hpp>
21 #include <boost/function.hpp>
22 #include <boost/shared_ptr.hpp>
25 #include <moof/math.hh>
26 #include <moof/timer.hh>
33 typedef boost::shared_ptr
<runloop
> runloop_ptr
;
37 * Represents a thread which may be running. You cannot instantiate a
38 * thread object directly; new threads are created by detaching functions
39 * using the detach() method. Once a thread is detached, it will continue
40 * running until the function returns. You don't need to keep the thread
41 * object you want to wait() or kill() the thread later.
47 typedef boost::function
<int(thread
&)> function
;
51 * Construct an invalid thread object which has no association with any
58 * Execute a function in a new thread.
59 * \param function The function to execute.
60 * \return The new thread, or an invalid thread if an error occurred.
62 static thread
detach(const function
& function
);
65 * Detach a new thread and run its runloop with an initial timer.
66 * \param timer The timer to schedule on the thread.
67 * \return The new thread, or an invalid thread if an error occurred.
69 static thread
detach(timer
& timer
);
73 * Wait for the thread to terminate, getting its return value. The
74 * thread will be invalidated.
75 * \return The integer value returned by the detached function.
82 SDL_WaitThread(thread_
, &i
);
90 * Forcefully kill the thread without giving it a chance to clean up
91 * after itself. The thread will be invalidated. Don't use this.
96 * Get whether or not the thread object is associated with a real
98 * \return True if the thread is valid, false otherwise.
100 bool is_valid() const
107 * Get a unique identifier for this thread, if it is valid.
108 * \return The identifier.
110 uint32_t identifier() const
112 return SDL_GetThreadID(thread_
);
116 * Get the unique identifier of the calling thread.
117 * \return The identifier.
119 static uint32_t current_identifier()
121 return SDL_ThreadID();
126 * Get the thread's runloop.
127 * \return The thread's runloop.
129 moof::runloop
& runloop() const;
132 * Get the runloop for the main thread.
133 * \return The runloop.
135 static moof::runloop
& main_runloop();
140 static void spawn(thread
* thread
);
141 static int run(void* arg
);
146 runloop_ptr runloop_
;
151 * An abstract class representing some task that is to be run
159 * Deconstruct the task.
161 virtual ~async_task() {}
164 * Get whether or not the task is done.
165 * \return True if the task is done, false otherwise.
167 virtual bool is_done() const = 0;
172 virtual void run() = 0;
175 * Block the current thread until the task is finished.
176 * \return A value representing the state of the finished task.
178 virtual int wait() = 0;
182 * An asynchronous task that is run to be executed in a separated thread.
189 * Get the thread object the task is executing in.
190 * \return The thread.
192 const class thread
& thread() const { return thread_
; }
195 * Block the current thread until the task thread is finished.
196 * \return The integer value returned by the task function.
200 return thread_
.wait();
206 class thread thread_
;
211 * A mutex to protect sensitive sections of code from threads which might
212 * otherwise cause unpredictable results.
222 mutex_(SDL_CreateMutex()) {}
225 * Deconstruct a mutex.
229 SDL_DestroyMutex(mutex_
);
234 * Block until the calling thread can secure exclusive access to the
235 * code protected by the mutex.
236 * \return True if the lock was acquired, false otherwise.
241 return (SDL_LockMutex(mutex_
) == 0);
245 * Unlock the mutex. Call this after the sensitive block of code to
246 * allow another thread to acquire the lock.
247 * \return True if the mutex was unlocked, false otherwise.
252 return (SDL_UnlockMutex(mutex_
) == 0);
257 * As an alternative method for locking, objects of this class will
258 * automagically release the lock if it is still locked at
259 * deconstruction. Therefore, it's generally safer to use this method
260 * since it makes it much more difficult to forget to unlock a mutex.
268 * \param mutex The mutex.
270 explicit lock(mutex
& mutex
, bool lock
= true) :
274 if (lock
) if (!acquire()) throw "mutex lock not acquired";
278 * Deconstruct a lock. The lock is automagically released if it is
283 if (is_locked_
) release();
288 * Try to acquire a lock on the mutex.
289 * \return True if the mutex was locked, false otherwise.
293 return (is_locked_
= mutex_
.acquire_lock());
298 * \return True if the mutex was unlocked, false otherwise.
302 bool result
= mutex_
.release_lock();
309 * Get whether or not the mutex is locked.
310 * \return True if the mutex is locked, false otherwise.
312 bool is_locked() const
323 friend class condition
;
331 friend class condition
;
336 * A class representing a condition variable.
343 * Construct a condition.
347 condition_
= SDL_CreateCond();
351 * Deconstruct a condition.
355 SDL_DestroyCond(condition_
);
360 * Unlock the mutex and wait for another thread to notify the thread,
361 * at which point the mutex will be re-locked and the method will
363 * \param mutex The mutex.
364 * \return True if the thread was notified, false otherwise.
366 bool wait(mutex
& mutex
)
368 return (SDL_CondWait(condition_
, mutex
.mutex_
) == 0);
372 * Unlock the mutex associated with a lock and wait for another thread
373 * to notify the thread, at which point the lock will be re-locked and
374 * the method will return.
375 * \param lock The lock.
376 * \return True if the thread was notified, false otherwise.
378 bool wait(mutex::lock
& lock
)
380 return (SDL_CondWait(condition_
, lock
.mutex_
.mutex_
) == 0);
384 * Unlock the mutex and wait for another thread to notify the thread,
385 * at which point the mutex will be re-locked and the method will
386 * return. If the thread was not notified before a certain number of
387 * seconds, the method will return anyway.
388 * \param mutex The mutex.
389 * \param timeout Number of seconds to wait.
390 * \return True if the thread was notified, false otherwise.
392 bool wait(mutex
& mutex
, scalar timeout
)
394 Uint32 ms
= timeout
* SCALAR(1000.0);
395 return (SDL_CondWaitTimeout(condition_
, mutex
.mutex_
, ms
) == 0);
399 * Unlock the mutex associated with a lock and wait for another thread
400 * to notify the thread, at which point the lock will be re-locked and
401 * the method will return. If the thread was not notified before a
402 * certain number of seconds, the method will return anyway.
403 * \param lock The lock.
404 * \param timeout Number of seconds to wait.
405 * \return True if the thread was notified, false otherwise.
407 bool wait(mutex::lock
& lock
, scalar timeout
)
409 Uint32 ms
= timeout
* SCALAR(1000.0);
410 return (SDL_CondWaitTimeout(condition_
,
411 lock
.mutex_
.mutex_
, ms
) == 0);
416 * Notify one other thread that is waiting on the condition.
417 * \return True on success, false otherwise.
421 return (SDL_CondSignal(condition_
) == 0);
425 * Notify all other threads that are waiting on the condition.
426 * \return True on success, false otherwise.
430 return (SDL_CondBroadcast(condition_
) == 0);
436 SDL_cond
* condition_
;
448 * Construct a semaphore.
449 * \param value The initial value of the semaphore.
451 explicit semaphore(uint32_t value
)
453 semaphore_
= SDL_CreateSemaphore(value
);
457 * Deconstruct a semaphore.
461 SDL_DestroySemaphore(semaphore_
);
466 * Block until the calling thread can secure exclusive access to the
467 * code protected by the semaphore.
468 * \return True if the lock was acquired, false otherwise.
473 return (SDL_SemWait(semaphore_
) == 0);
477 * Block until the calling thread can secure exclusive access to the
478 * code protected by the semaphore, or until the timeout expires.
479 * \param timeout Number of seconds to try.
480 * \return True if the lock was acquired, false otherwise.
482 bool acquire_lock(scalar timeout
)
484 Uint32 ms
= timeout
* SCALAR(1000.0);
485 return (SDL_SemWaitTimeout(semaphore_
, ms
) == 0);
489 * Unlock the semaphore. Call this after the sensitive block of code
490 * to allow another thread to acquire the lock.
491 * \return True if the semaphore was unlocked, false otherwise.
496 return (SDL_SemPost(semaphore_
) == 0);
500 * Try to lock the semaphore, but don't block if the lock is not
501 * immediately available.
502 * \return True if the semaphore was locked, false otherwise.
506 return (SDL_SemTryWait(semaphore_
) == 0);
510 * As an alternative method for locking, objects of this class will
511 * automagically release the lock if it is still locked at
512 * deconstruction. Therefore, it's generally safer to use this method
513 * since it makes it much more difficult to forget to unlock a
522 * \param semaphore The semaphore.
524 explicit lock(semaphore
& semaphore
, bool lock
= true) :
525 semaphore_(semaphore
),
528 if (lock
) if (!acquire()) throw "semaphore lock not acquired";
532 * Deconstruct a lock. The lock is automagically released if it is
537 if (is_locked_
) release();
542 * Try to acquire a lock on the semaphore.
543 * \return True if the semaphore was locked, false otherwise.
547 return (is_locked_
= semaphore_
.acquire_lock());
552 * \return True if the semaphore was unlocked, false otherwise.
556 bool result
= semaphore_
.release_lock();
562 * Get whether or not the semaphore is locked.
563 * \return True if the semaphore is locked, false otherwise.
565 bool is_locked() const
573 semaphore
& semaphore_
;
585 #define MOOF_DECLARE_MUTEX(M) moof::mutex M
586 #define MOOF_DECLARE_STATIC_MUTEX(M) static moof::mutex M
587 #define MOOF_MUTEX_LOCK(M) moof::mutex::lock lock_##M(M)
589 #define MOOF_DECLARE_MUTEX(M)
590 #define MOOF_DECLARE_STATIC_MUTEX(M)
591 #define MOOF_MUTEX_LOCK(M)
597 #endif // _MOOF_THREAD_HH_
This page took 0.05604 seconds and 4 git commands to generate.