[AD] public thread API |
[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]
Hi, A couple of weeks (months) ago there was a re-suggestion to expose a thread API. At that time I started writing down the docs for such a thing then forgot about it. Here it is, in source and rendered HTML. I think I was the only one who had objections to including a thread API, so whoever feels like working on this should go right ahead. The internal API mostly matches this already. * initialisation functions take preallocated objects; should they allocate on the heap and return pointers instead? * I didn't stray from the pthreads word order; should we? Peter
% Threading API Allegro 4.9 [is proposed to] include a simple cross-platform threading interface. It is a thin layer on top of two threading APIs: Windows threads and POSIX Threads (pthreads). Enforcing a consistent semantics on all platforms would be difficult at best, hence the behaviour of the following functions will differ subtly on different platforms (more so than usual). Your best bet is to be aware of this and code to the intersection of the semantics and avoid edge cases. ------------------------------------------------------------------------------- [ALLEGRO_THREAD]: #ALLEGRO_THREAD ### ALLEGRO_THREAD typedef struct ALLEGRO_THREAD ALLEGRO_THREAD; [ALLEGRO_MUTEX]: #ALLEGRO_MUTEX ### ALLEGRO_MUTEX typedef struct ALLEGRO_MUTEX ALLEGRO_MUTEX; [ALLEGRO_COND]: #ALLEGRO_COND ### ALLEGRO_COND typedef struct ALLEGRO_COND ALLEGRO_COND; [ALLEGRO_COND_TIMEOUT]: #ALLEGRO_COND_TIMEOUT ### ALLEGRO_COND_TIMEOUT typedef struct ALLEGRO_COND_TIMEOUT ALLEGRO_COND_TIMEOUT; Don't know yet. [al_thread_create]: #al_thread_create ### al_thread_create bool al_thread_create(ALLEGRO_THREAD *thread, void (*proc)(ALLEGRO_THREAD *thread, void *arg), void *arg); Spawn a new thread which begins executing `proc`. The new thread is passed its own thread handle and the value `arg`. *Return value:* Returns true if the thread was created, false if there was an error. *See also:* [al_thread_join]. *Comment:* `proc` should return an exit status. [al_thread_join]: #al_thread_join ### al_thread_join void al_thread_join(ALLEGRO_THREAD *thread); Wait for the thread to finish executing. *See also:* [al_thread_should_stop]. *Comment:* Should return exit status of the proc. [al_thread_should_stop]: #al_thread_should_stop ### al_thread_should_stop bool al_thread_should_stop(ALLEGRO_THREAD *thread); Check if another thread is waiting for `thread` to stop. Threads which run in a loop should check this periodically and act on it when convenient. *Return value:* Return true if another thread has called `al_thread_join` on this thread. *Note:* We don't support forceful killing of threads. ------------------------------------------------------------------------------- [al_mutex_init]: #al_mutex_init ### al_mutex_init void al_mutex_init(ALLEGRO_MUTEX *mutex); Initialise the mutex object (a mutual exclusion device). The mutex may or may not support "recursive" locking. *See also:* [al_mutex_init_recursive]. [al_mutex_init_recursive]: #al_mutex_init_recursive ### al_mutex_init_recursive void al_mutex_init_recursive(ALLEGRO_MUTEX *mutex); Initialise the mutex object (a mutual exclusion device), with support for "recursive" locking. That is, the mutex will count the number of times it has been locked by the same thread. If the caller tries to acquire a lock on the mutex when it already holds the lock then the count is incremented. The mutex is only unlocked when the thread releases the lock on the mutex an equal number of times, i.e. the count drops down to zero. *See also:* [al_mutex_init]. [al_mutex_lock]: #al_mutex_lock ### al_mutex_lock void al_mutex_lock(ALLEGRO_MUTEX *mutex); Acquire the lock on `mutex`. If the mutex is already locked by another thread, the call will block until the mutex becomes available and locked. If the mutex is already locked by the calling thread, then the behaviour depends on whether the mutex was initialised with `al_mutex_init` or `al_mutex_init_recursive`. In the former case, the behaviour is undefined; the most likely behaviour is deadlock. In the latter case, the count in the mutex will be incremented and the call will return immediately. *See also:* [al_mutex_unlock]. *Comment:* We don't yet have al_mutex_trylock. [al_mutex_unlock]: #al_mutex_unlock ### al_mutex_unlock void _al_mutex_unlock(_AL_MUTEX *mutex); Release the lock on `mutex` if the calling thread holds the lock on it. If the calling thread doesn't hold the lock, or if the mutex is not locked, undefined behaviour results. *See also:* [al_mutex_lock]. [al_mutex_destroy]: #al_mutex_destroy ### al_mutex_destroy void al_mutex_destroy(ALLEGRO_MUTEX *mutex); Free the resources used by the mutex. The mutex should be unlocked. Destroying a locked mutex results in undefined behaviour. ------------------------------------------------------------------------------- [al_cond_init]: #al_cond_init ### al_cond_init void al_cond_init(ALLEGRO_COND *cond); Initialise a condition variable. Initialising a condition variable which is already initialised results in undefined behaviour. [al_cond_destroy]: #al_cond_destroy ### al_cond_destroy void al_cond_destroy(ALLEGRO_COND *cond); Destroy a condition variable. Destroying a condition variable which has threads block on it results in undefined behaviour. [al_cond_wait]: #al_cond_wait ### al_cond_wait void al_cond_wait(ALLEGRO_COND *cond, ALLEGRO_MUTEX *mutex); On entering this function, `mutex` must be locked by the calling thread. The function will atomically release `mutex` and block on `cond`. The function will return when `cond` is "signalled", acquiring the lock on the mutex in the process. Example of proper use: al_mutex_lock(mutex); while (something_not_true) { al_cond_wait(cond, mutex); } do_something(); al_mutex_unlock(mutex); The mutex should be locked before checking the condition, and should be rechecked `al_cond_wait` returns. `al_cond_wait` can return for other reasons than the condition becoming true (e.g. the process was signalled). If multiple threads are blocked on the condition variable, the condition may no longer be true by the time the second and later threads are unblocked. Remember not to unlock the mutex prematurely. *See also:* [al_cond_timedwait], [al_cond_broadcast], [al_cond_signal]. [al_cond_timedwait]: #al_cond_timedwait ### al_cond_timedwait int al_cond_timedwait(ALLEGRO_COND *cond, ALLEGRO_MUTEX *mutex, const ALLEGRO_COND_TIMEOUT timeout); Like `al_cond_wait` but the call can time out. *Comment:* Finish the description. [al_cond_broadcast]: #al_cond_broadcast ### al_cond_broadcast void al_cond_broadcast(ALLEGRO_COND *cond); Unblock all threads currently waiting on a condition variable. That is, broadcast that some condition which those threads were waiting for has become true. *See also:* [al_cond_signal]. *Note:* The pthreads spec says to lock the mutex associated with `cond` before signalling for predictable scheduling behaviour. [al_cond_signal]: #al_cond_signal ### al_cond_signal void al_cond_signal(ALLEGRO_COND *cond); Unblock at least one thread waiting on a condition variable. Generally you should use `al_cond_broadcast` but `al_cond_signal` may be more efficient when it's applicable. *See also:* [al_cond_broadcast]. ------------------------------------------------------------------------------- <!-- vim: set ts=8 sts=4 sw=4 tw=76 et: -->Title: Threading API
Allegro 4.9 [is proposed to] include a simple cross-platform threading interface. It is a thin layer on top of two threading APIs: Windows threads and POSIX Threads (pthreads). Enforcing a consistent semantics on all platforms would be difficult at best, hence the behaviour of the following functions will differ subtly on different platforms (more so than usual). Your best bet is to be aware of this and code to the intersection of the semantics and avoid edge cases.
typedef struct ALLEGRO_THREAD ALLEGRO_THREAD;
typedef struct ALLEGRO_MUTEX ALLEGRO_MUTEX;
typedef struct ALLEGRO_COND ALLEGRO_COND;
typedef struct ALLEGRO_COND_TIMEOUT ALLEGRO_COND_TIMEOUT;
Don't know yet.
bool al_thread_create(ALLEGRO_THREAD *thread,
void (*proc)(ALLEGRO_THREAD *thread, void *arg),
void *arg);
Spawn a new thread which begins executing proc
. The new thread is passed its own thread handle and the value arg
.
Return value:
Returns true if the thread was created, false if there was an error.
See also: al_thread_join.
Comment: proc
should return an exit status.
void al_thread_join(ALLEGRO_THREAD *thread);
Wait for the thread to finish executing.
See also: al_thread_should_stop.
Comment: Should return exit status of the proc.
bool al_thread_should_stop(ALLEGRO_THREAD *thread);
Check if another thread is waiting for thread
to stop. Threads which run in a loop should check this periodically and act on it when convenient.
Return value:
Return true if another thread has called al_thread_join
on this thread.
Note: We don't support forceful killing of threads.
void al_mutex_init(ALLEGRO_MUTEX *mutex);
Initialise the mutex object (a mutual exclusion device). The mutex may or may not support "recursive" locking.
See also: al_mutex_init_recursive.
void al_mutex_init_recursive(ALLEGRO_MUTEX *mutex);
Initialise the mutex object (a mutual exclusion device), with support for "recursive" locking. That is, the mutex will count the number of times it has been locked by the same thread. If the caller tries to acquire a lock on the mutex when it already holds the lock then the count is incremented. The mutex is only unlocked when the thread releases the lock on the mutex an equal number of times, i.e. the count drops down to zero.
See also: al_mutex_init.
void al_mutex_lock(ALLEGRO_MUTEX *mutex);
Acquire the lock on mutex
. If the mutex is already locked by another thread, the call will block until the mutex becomes available and locked.
If the mutex is already locked by the calling thread, then the behaviour depends on whether the mutex was initialised with al_mutex_init
or al_mutex_init_recursive
. In the former case, the behaviour is undefined; the most likely behaviour is deadlock. In the latter case, the count in the mutex will be incremented and the call will return immediately.
See also: al_mutex_unlock.
Comment: We don't yet have al_mutex_trylock.
void _al_mutex_unlock(_AL_MUTEX *mutex);
Release the lock on mutex
if the calling thread holds the lock on it.
If the calling thread doesn't hold the lock, or if the mutex is not locked, undefined behaviour results.
See also: al_mutex_lock.
void al_mutex_destroy(ALLEGRO_MUTEX *mutex);
Free the resources used by the mutex. The mutex should be unlocked. Destroying a locked mutex results in undefined behaviour.
void al_cond_init(ALLEGRO_COND *cond);
Initialise a condition variable.
Initialising a condition variable which is already initialised results in undefined behaviour.
void al_cond_destroy(ALLEGRO_COND *cond);
Destroy a condition variable.
Destroying a condition variable which has threads block on it results in undefined behaviour.
void al_cond_wait(ALLEGRO_COND *cond, ALLEGRO_MUTEX *mutex);
On entering this function, mutex
must be locked by the calling thread. The function will atomically release mutex
and block on cond
. The function will return when cond
is "signalled", acquiring the lock on the mutex in the process.
Example of proper use:
al_mutex_lock(mutex);
while (something_not_true) {
al_cond_wait(cond, mutex);
}
do_something();
al_mutex_unlock(mutex);
The mutex should be locked before checking the condition, and should be rechecked al_cond_wait
returns. al_cond_wait
can return for other reasons than the condition becoming true (e.g. the process was signalled). If multiple threads are blocked on the condition variable, the condition may no longer be true by the time the second and later threads are unblocked. Remember not to unlock the mutex prematurely.
See also: al_cond_timedwait, al_cond_broadcast, al_cond_signal.
int al_cond_timedwait(ALLEGRO_COND *cond, ALLEGRO_MUTEX *mutex,
const ALLEGRO_COND_TIMEOUT timeout);
Like al_cond_wait
but the call can time out.
Comment: Finish the description.
void al_cond_broadcast(ALLEGRO_COND *cond);
Unblock all threads currently waiting on a condition variable. That is, broadcast that some condition which those threads were waiting for has become true.
See also: al_cond_signal.
Note: The pthreads spec says to lock the mutex associated with cond
before signalling for predictable scheduling behaviour.
void al_cond_signal(ALLEGRO_COND *cond);
Unblock at least one thread waiting on a condition variable.
Generally you should use al_cond_broadcast
but al_cond_signal
may be more efficient when it's applicable.
See also: al_cond_broadcast.
body { margin: auto; padding-right: 1em; padding-left: 1em; max-width: 44em; border-left: 1px solid black; border-right: 1px solid black; color: black; font-family: Verdana, sans-serif; font-size: 100%; line-height: 140%; color: #333; } pre { border: 1px dotted gray; background-color: #ececec; color: #1111111; padding: 0.5em; } code { font-family: monospace; } h1 a, h2 a, h3 a, h4 a, h5 a { text-decoration: none; color: #7a5ada; } h1, h2, h3, h4, h5 { font-family: verdana; font-weight: bold; border-bottom: 1px dotted black; color: #7a5ada; } h1 { font-size: 130%; } h2 { font-size: 110%; } h3 { font-size: 95%; } h4 { font-size: 90%; font-style: italic; } h5 { font-size: 90%; font-style: italic; } h1.title { font-size: 200%; font-weight: bold; padding-top: 0.2em; padding-bottom: 0.2em; text-align: left; border: none; } dt code { font-weight: bold; } dd p { margin-top: 0; } #footer { padding-top: 1em; font-size: 70%; color: gray; text-align: center; }
Mail converted by MHonArc 2.6.19+ | http://listengine.tuxfamily.org/ |