introduction to synchronization routines in the Threads Library
cc [options] -Kthread file
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
The following synchronization mechanisms are specified:
mutual exclusion locks (mutex 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.
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 not prevented from modifying the shared data.
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
A mutual exclusion lock, or ``mutex'',
is 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.
Spin locks and recursive
mutex locks are variations of the mutex lock.
A condition variable is a
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
buffer is not empty.
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.
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.
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(SYNCH)
(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 single processor system.
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(SYNCH))
will block the caller until the lock is available.
When a spin lock is already locked,
the locking routine (_spin_lock(SYNCH))
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 preempted 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 single processor system.
In the best case, a spin lock on a single processor system will waste resources,
slowing down the owner of the lock;
in the worst case, it will deadlock the processor.
Recursive mutex locks
Recursive mutual exclusion locks, or ``rmutexe''s,
are mutexes that can be locked recursively.
That is, a thread that has locked an rmutex
can 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 can lock it again while the rmutex is locked;
other threads are denied access as with ordinary mutexes.
Each rmutex_lock(SYNCH) or rmutex_trylock(SYNCH) 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.
The Threads Library provides a mechanism
for tracing significant library events.
Calls to all Threads Library interfaces
can be traced.
The Threads Library does not guarantee to preserve errno
The synch library is not part of any currently supported standard.
© 2005 The SCO Group, Inc. All rights reserved.
SCO OpenServer Release 6.0.0 - 01 June 2005