AG_Threads
— agar
threads support
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.
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.
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)).
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.
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.
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.
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:
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);
The AG_Threads
interface first appeared in
Agar 1.0