SYNOPSIS
#include <agar/core.h>
DESCRIPTION
On platforms with threads support, Agar can be compiled with support for
multithreading.
In a threaded build, Agar API calls can be considered
free-threaded (safe to use from different threads without need for application-level
synchronization) unless documented otherwise.
Even though calls are free-threaded, application-level synchronization (calls to AG_ObjectLock(3)) may still be needed in some cases. See EXAMPLES for some examples of thread-unsafe vs. thread-safe usages.
Even though calls are free-threaded, application-level synchronization (calls to AG_ObjectLock(3)) may still be needed in some cases. See EXAMPLES for some examples of thread-unsafe vs. thread-safe usages.
CONVENTIONS ↑
Agar function calls are free-threaded unless mentioned otherwise.
The AG_Object(3) system provides a per-object recursive mutex which is implicitely acquired before invoking object methods or processing events.
The AG_Object(3) system provides a per-object recursive mutex which is implicitely acquired before invoking object methods or processing events.
THREADS INTERFACE ↑
When compiled with threads support, Agar provides a portable, minimal interface
to the operating system's native threads interface.
These functions follow Agar's standard error-handling style (see
AG_Intro(3)).
MUTEXES ↑
Mutexes (MUTual EXclusion devices) are commonly used to protect shared
data structure against concurrent modifications.
void AG_MutexInit (AG_Mutex *mutex)
int AG_MutexTryInit (AG_Mutex *mutex)
void AG_MutexInitRecursive (AG_Mutex *mutex)
int AG_MutexTryInitRecursive (AG_Mutex *mutex)
void AG_MutexDestroy (AG_Mutex *mutex)
void AG_MutexLock (AG_Mutex *mutex)
int AG_MutexTryLock (AG_Mutex *mutex)
void AG_MutexUnlock (AG_Mutex *mutex)
The AG_MutexInit() function initializes a mutex structure. AG_MutexInitRecursive() initializes a recursive mutex (a mutex with a reference count), which allows nested AG_MutexLock() calls.
AG_MutexDestroy() frees all resources allocated for a mutex.
AG_MutexLock() and AG_MutexUnlock() respectively acquire and release a mutex.
AG_MutexTryLock() tries to acquire a mutex without blocking and immediately returns 0 on success. On failure, the function returns -1, but does not set any error message (so AG_GetError(3) should not be used).
void AG_MutexInit (AG_Mutex *mutex)
int AG_MutexTryInit (AG_Mutex *mutex)
void AG_MutexInitRecursive (AG_Mutex *mutex)
int AG_MutexTryInitRecursive (AG_Mutex *mutex)
void AG_MutexDestroy (AG_Mutex *mutex)
void AG_MutexLock (AG_Mutex *mutex)
int AG_MutexTryLock (AG_Mutex *mutex)
void AG_MutexUnlock (AG_Mutex *mutex)
The AG_MutexInit() function initializes a mutex structure. AG_MutexInitRecursive() initializes a recursive mutex (a mutex with a reference count), which allows nested AG_MutexLock() calls.
AG_MutexDestroy() frees all resources allocated for a mutex.
AG_MutexLock() and AG_MutexUnlock() respectively acquire and release a mutex.
AG_MutexTryLock() tries to acquire a mutex without blocking and immediately returns 0 on success. On failure, the function returns -1, but does not set any error message (so AG_GetError(3) should not be used).
CONDITION VARIABLES ↑
void AG_CondInit (AG_Cond *cv)
int AG_CondTryInit (AG_Cond *cv)
void AG_CondDestroy (AG_Cond *cv)
void AG_CondBroadcast (AG_Cond *cv)
void AG_CondSignal (AG_Cond *cv)
int AG_CondWait (AG_Cond *cv, AG_Mutex *m)
int AG_CondTimedWait (AG_Cond *cv, AG_Mutex *m, const struct timespec *t)
AG_CondInit() initializes a condition variable structure.
AG_CondDestroy() releases resources allocated for a condition variable.
AG_CondBroadcast() unblock all threads which are currently blocked waiting on cv. AG_CondSignal() unblocks at least one thread currently blocked waiting on cv.
AG_CondWait() blocks the calling thread until cv is signaled. The AG_CondTimedWait() variant will not block for more than the specified amount of time.
All of these functions will raise a fatal condition if an error is encountered.
THREADS ↑
void AG_ThreadCreate (AG_Thread *th, void *(*fn)(void *arg), void *arg)
int AG_ThreadTryCreate (AG_Thread *th, void *(*fn)(void *arg), void *arg)
void AG_ThreadCancel (AG_Thread th)
int AG_ThreadTryCancel (AG_Thread th)
void AG_ThreadJoin (AG_Thread th, void **exitVal)
int AG_ThreadTryJoin (AG_Thread th, void **exitVal)
void AG_ThreadExit (void *exitVal)
void AG_ThreadKill (AG_Thread th, int signal)
AG_Thread AG_ThreadSelf (void)
int AG_ThreadEqual (AG_Thread a, AG_Thread b)
AG_ThreadCreate() creates a new thread executing fn. The optional argument arg is passed to fn.
The AG_ThreadCancel() routine requests that the specified thread be cancelled. If the given thread is invalid, a fatal error is raised.
The AG_ThreadJoin() function suspends the execution of the current thread until th terminates. When it does, the value passed to AG_ThreadExit() is made available in exitVal.
AG_ThreadExit() terminates the current thread. exitVal is an optional user pointer.
AG_ThreadKill() sends a signal to the specified thread.
AG_ThreadSelf() returns the identifier of the current (caller's) thread. AG_ThreadEqual() returns 1 if the identifiers a and b both refer to the same thread, or 0 if they differ.
THREAD-SPECIFIC VARIABLES ↑
void AG_ThreadKeyCreate (AG_ThreadKey *key, void (*destructor)(void *))
int AG_ThreadKeyTryCreate (AG_ThreadKey *key, void (*destructor)(void *))
void AG_ThreadKeyDelete (AG_ThreadKey key)
int AG_ThreadKeyTryDelete (AG_ThreadKey key)
void * AG_ThreadKeyGet (AG_ThreadKey key)
void AG_ThreadKeySet (AG_ThreadKey key, const void *value)
int AG_ThreadKeyTrySet (AG_ThreadKey key, const void *value)
AG_ThreadKeyCreate() initializes a key (i.e., a handle) to a thread-specific value. The handle itself is accessible to all threads. The thread-specific value (i.e., the value specified by AG_ThreadKeySet(), and which defaults to NULL) will persist only for the life of the thread. If an optional destructor is given, that function will be called (with the thread-specific value as its argument), when the thread exists.
The AG_ThreadKeyDelete() function releases resources allocated for a key.
AG_ThreadKeyGet() returns the thread-specific value associated with key.
AG_ThreadKeySet() sets a thread-specific value with key.
EXAMPLES ↑
The following code uses the return value of a VFS lookup in a manner
which is
not thread-safe.
A race condition exists between the
AG_ObjectFind() call and the following access:
The following code accesses the returned object safely by acquiring the mutex of the VFS root object (which protects the entire VFS linkage):
AG_Object *o; o = AG_ObjectFind(root, "/Foo"); if (o != NULL) { /* ... */ } /* UNSAFE access */
The following code accesses the returned object safely by acquiring the mutex of the VFS root object (which protects the entire VFS linkage):
AG_Object *o; AG_ObjectLock(root); o = AG_ObjectFind(root, "/Foo"); if (o != NULL) { /* ... */ } /* Safe access */ AG_ObjectUnlock(root);
SEE ALSO ↑
HISTORY ↑
The
AG_Threads interface first appeared in
Agar 1.0