synch(3synch) synch(3synch)
NAME
synch - introduction to synchronization routines in the
Threads Library
SYNOPSIS
cc [options] -Kthread file
#include <synch.h>
DESCRIPTION
The Threads Library supplies routines for thread management
that allow a programmer to implement parallel algorithms
conveniently. In addition, the Threads Library supplies
user-level synchronization routines that allow coordination of
threads within a process or across processes. The
synchronization interfaces allow coordination of threads
within a process as well as coordination of threads in
different processes. The following synchronization mechanisms
are specified:
mutual exclusion locks (mutex locks)
condition variables
semaphores
reader-writer locks
barriers
spin locks
recursive mutual exclusion locks (rmutex locks)
Most of these mechanisms can be initialized to be of one of
two types: USYNC_THREAD or USYNC_PROCESS. USYNC_THREAD
mechanisms should be used only by threads within the current
process, whether or not the synchronization objects are in
shared memory. USYNC_PROCESS mechanisms can be used by
threads in different processes.
Each of these mechanisms is described briefly below, and in
more detail on individual manual pages.
In all cases, data is protected by convention; a thread not
following the order of acquiring a lock/semaphore, modifying
or using the resource, then releasing the lock/semaphore is
Copyright 1994 Novell, Inc. Page 1
synch(3synch) synch(3synch)
not prevented from modifying the shared data.
Error Handling
None of the Threads Library user synchronization routines set
errno; most return an error number if an error is encountered.
This discourages use of errno, which is non-reentrant. The
Threads Library does not guarantee to preserve errno across
calls.
Mutual Exclusion Locks
Mutual exclusion locks, or mutexes, are a synchronization
mechanism used to serialize the execution of threads. They
are typically used to ensure that only one thread at a time is
operating on a shared datum. When mutexes are locked before
and unlocked after every access to shared data, the integrity
of that data is assured. Note that mutexes protect data only
when the convention of acquiring and releasing the mutex is
faithfully followed before and after any access of the data.
See mutex(3synch), mutex_destroy(3synch), mutex_init(3synch),
mutex_lock(3synch), mutex_trylock(3synch), and
mutex_unlock(3synch).
Spin locks and recursive mutex locks are variations of the
mutex lock.
Condition Variables
A condition variable is a user-level synchronization mechanism
used to communicate information between cooperating threads,
making it possible for a thread to suspend its execution while
waiting for an event or condition. For example, the consumer
in a producer-consumer algorithm might need to wait for the
producer by waiting for the condition buffer is not empty.
See condition(3synch), cond_broadcast(3synch),
cond_destroy(3synch), cond_init(3synch), cond_signal(3synch),
cond_timedwait(3synch), and cond_wait(3synch).
Reader-Writer Locks
Reader-writer locks allow many threads to have simultaneous
read-only access to data, while allowing only one thread to
have write access at any time. They are typically used to
protect data that is searched more often than it is changed.
Copyright 1994 Novell, Inc. Page 2
synch(3synch) synch(3synch)
See rwlock(3synch), rw_rdlock(3synch), rw_tryrdlock(3synch),
rw_trywrlock(3synch), rw_unlock(3synch), rw_wrlock(3synch),
rwlock_destroy(3synch), and rwlock_init(3synch).
Semaphores
Conceptually, a semaphore is a non-negative integer count.
Semaphores are typically used to coordinate access to
resources. The semaphore count is initialized with sema_init
to the number of free resources. Threads then atomically
increment the count with sema_post when resources are released
and atomically decrement the count with sema_wait when
resources are acquired. When the semaphore count becomes
zero, indicating that no more resources are present, threads
trying to decrement the semaphore with sema_wait will block
until the count becomes greater than zero.
See semaphore(3synch), sema_destroy(3synch),
sema_init(3synch), sema_post(3synch), sema_trywait(3synch),
and sema_wait(3synch).
Barriers
Barriers provide a simple coordination mechanism for threads.
Threads wait at a barrier until a specified number of threads
have reached the barrier, then they all resume execution.
There are two types of barriers: blocking and spinning.
Threads waiting at a blocking barrier are put to sleep, or
blocked, until the specified number of threads have reached
the barrier. Threads waiting at a spinning barrier busy-wait,
or spin, until the specified number of threads have reached
the barrier.
When a thread calls barrier_wait (for a blocking barrier) or
_barrier_spin (for a spinning barrier) it is said to have
reached the barrier.
Because spinning barriers waste resources, most applications
should use blocking barriers instead of spinning barriers.
Spinning barriers should only be used when all participating
threads will reach the barrier at approximately the same time.
Spinning barriers should never be used on a uniprocessor.
See barrier(3synch), barrier_destroy(3synch),
barrier_init(3synch), _barrier_spin(3synch),
_barrier_spin_destroy(3synch), _barrier_spin_init(3synch), and
Copyright 1994 Novell, Inc. Page 3
synch(3synch) synch(3synch)
barrier_wait(3synch).
Spin Locks
Spin locks are a type of mutex. The difference between spin
locks and ordinary mutex locks is in their locking routines.
When a mutex is already locked, the locking routine
(mutex_lock) will block the caller until the lock is
available. When a spin lock is already locked, the locking
routine (_spin_lock) will busy-wait, or spin, in a loop,
testing if the lock has become available. Such spinning
wastes processor cycles and can slow processors doing useful
work, including the processor holding the lock, by consuming
communication bandwidth.
Because spin locks waste system resources, most applications
should use mutexes instead of spin locks for mutual exclusion.
However, spin locks are useful when:
sleep is not permitted
the critical section is small, so that the expected spin
is less costly than blocking and resuming the thread
no other work is available
Spin locks should only be used when there is a guarantee that
the thread will not be pre-empted or blocked while holding a
spin lock. It is the responsibility of each application to
unlock all spin locks before calling sleep or blocking
routines.
Spin locks must not be used on a uniprocessor. In the best
case, a spin lock on a uniprocessor will waste resources,
slowing down the owner of the lock; in the worst case, it will
deadlock the processor.
See _spin(3synch), _spin_destroy(3synch), _spin_init(3synch),
_spin_lock(3synch), _spin_trylock(3synch), and
_spin_unlock(3synch).
Recursive Mutex Locks
Recursive mutual exclusion locks, or rmutexes, are mutexes
that can be locked recursively. That is, a thread that has
locked an rmutex may lock it again without releasing it. The
thread that has locked an rmutex is referred to as the owner
of the rmutex. Only the owner of an rmutex may lock it again
Copyright 1994 Novell, Inc. Page 4
synch(3synch) synch(3synch)
while the rmutex is locked; other threads are denied access as
with ordinary mutexes. Each rmutex_lock or rmutex_trylock
call must be matched by a corresponding rmutex_unlock before
the rmutex is made available to threads other than the owner.
Note that rmutexes, like mutexes, protect data only when the
convention of acquiring the rmutex is faithfully followed
before any access of the data.
See rmutex(3synch), rmutex_destroy(3synch),
rmutex_init(3synch), rmutex_lock(3synch),
rmutex_trylock(3synch), and rmutex_unlock(3synch).
Tracing Mechanism
The Threads Library provides a mechanism for tracing
significant library events. Calls to all Threads Library
interfaces can be traced. See thread_trace(4).
USAGE
Warnings
The Threads Library does not guarantee to preserve errno
across calls.
REFERENCES
barrier(3synch), barrier_destroy(3synch),
barrier_init(3synch), _barrier_spin(3synch),
_barrier_spin_destroy(3synch), _barrier_spin_init(3synch),
barrier_wait(3synch), condition(3synch),
cond_broadcast(3synch), cond_destroy(3synch),
cond_init(3synch), cond_signal(3synch),
cond_timedwait(3synch), cond_wait(3synch), mutex(3synch),
mutex_destroy(3synch), mutex_init(3synch), mutex_lock(3synch),
mutex_trylock(3synch), mutex_unlock(3synch), rmutex(3synch),
rmutex_destroy(3synch), rmutex_init(3synch),
rmutex_lock(3synch), rmutex_trylock(3synch),
rmutex_unlock(3synch), rwlock(3synch), rw_rdlock(3synch),
rw_tryrdlock(3synch), rw_trywrlock(3synch), rw_unlock(3synch),
rw_wrlock(3synch), rwlock_destroy(3synch),
rwlock_init(3synch), semaphore(3synch), sema_destroy(3synch),
sema_init(3synch), sema_post(3synch), sema_trywait(3synch),
sema_wait(3synch), _spin(3synch), _spin_destroy(3synch),
_spin_init(3synch), _spin_lock(3synch), _spin_trylock(3synch),
_spin_unlock(3synch), thread(3thread), thread_trace(4)
Copyright 1994 Novell, Inc. Page 5