Intro(3pthread)
Intro --
introduction to the POSIX Threads Library
Synopsis
cc [options] -Kthread file
#include <pthread.h>
Description
POSIX Threads
The Threads Library supplies routines for thread management
that allow a programmer to implement parallel algorithms conveniently.
In addition, user-level synchronization routines
are provided that allow coordination
of threads either within a process or across processes.
The (3pthread) man pages describe the
POSIX Threads APIs.
The UNIX International Threads APIs
are described in the (3thread) and (3synch) man pages.
It is good practice to use either one or the other set
consistently in an application.
What is a thread?
A thread-of-control, or thread for short,
is a sequence of instructions and associated data
that is scheduled and executed as an independent entity.
Every UNIX process linked with the Threads Library
contains at least one, and possibly many, threads.
Threads within a process share the address space of the process.
Processes also contain one or more lightweight processes (LWPs),
which are independently scheduled by the operating system kernel,
and which share address space
and other resources.
[see
_lwp_create(2)].
LWPs are the execution entities for threads.
When a thread executes, it is associated with an LWP.
We also say that an LWP picks up a thread for execution.
Bound and multiplexed threads
By default, the Threads Library multiplexes threads onto LWPs.
That is, when a thread runs,
it will be temporarily associated with any LWP in a pool
of available LWPs within the process.
The number of LWPs available in the pool
is called the degree or the level of concurrency.
These multiplexed threads are created with the
PTHREAD_SCOPE_PROCESS contentionscope.
Users can request a change in the level of concurrency
with
pthread_setconcurrency(3pthread).
A thread can also be bound to an LWP
for its lifetime [see
pthread_attr_setscope(3pthread)].
Bound threads have the properties of the underlying LWP,
therefore, a bound thread uses operating system scheduling.
These bound threads are created with the
PTHREAD_SCOPE_SYSTEM contentionscope.
The Threads Library schedules multiplexed threads
(see ``Thread Scheduling,'' below).
When a program is linked with the Threads Library,
an initial thread is created to execute the main function.
This initial thread is a multiplexed thread.
In certain cases, such as when competing for synchronization objects
bound threads are given scheduling priority over multiplexed threads
to make better use of system resources.
Thread creation
pthread_create(3pthread)
creates new threads.
Both multiplexed and bound threads can be created.
The caller can supply a stack for the thread to run on,
or the library will supply one.
The library does not check for stack overflow
for stacks supplied by the user,
but a SIGSEGV signal can be generated
if a thread overflows a library-allocated stack.
Every thread has an ID,
which is recognized only within the current process.
pthread_self(3pthread)
returns the ID of the calling thread.
Sibling threads
Threads within a process are siblings.
Unlike processes,
where a parent process creates a child process
for which it must
wait(2),
threads create siblings for which they do not have to wait.
Sibling threads can be awaited with
pthread_join(3pthread)
(see below), but this is optional.
Thread exit and process exit
pthread_exit(3pthread)
causes the calling thread to terminate its execution.
A process containing threads will terminate
in any of the following four circumstances:
-
When the last thread terminates,
the process exits.
-
If any thread calls
exit(2)
directly,
the process and all its threads and LWPs will exit immediately.
-
If the initial thread terminates without calling pthread_exit,
exit will be called implicitly,
causing the entire process to exit.
-
If the thread receives a signal
whose disposition is to terminate the process,
the process will exit.
Joining or waiting for a thread
A thread uses
pthread_join(3pthread)
to wait for another thread
to exit
and to retrieve its exit value.
The term ``join'' emphasizes the sibling relationship
between threads.
When one thread waits for another,
in effect they join control paths.
Threads are joinable by default,
but if they are created in the detached state
(see
pthread_attr_setdetachstate(3pthread)),
they cannot be joined.
If a thread will not be joined, it should be created in the
detached state to allow resources associated with the thread to be reused
after the thread terminates.
Thread scheduling
The Threads Library supports three scheduling policies:
-
time-sharing (SCHED_TS or SCHED_OTHER)
-
round-robin (SCHED_RR)
-
first-in-first-out (SCHED_FIFO)
Multiplexed threads must run under the time-sharing policy.
Bound threads can run under any of the policies.
See
pthread_attr_setschedpolicy(3pthread)
or
pthread_setschedparam(3pthread)
for details.
A thread can set its scheduling policy and priority
with
pthread_setschedparam(3pthread).
It can retrieve its scheduling policy and priority
with
pthread_getschedparam(3pthread).
sched_yield(3pthread)
causes a thread to stop executing
to allow another eligible thread to run.
The Threads Library does not protect against priority inversion.
That is, it is possible for a thread to be blocked
waiting for a lower priority thread to release a resource.
Error handling
In general, the Threads Library routines do not set errno;
the exceptions are the Posix semaphore routines (those with names
starting with the prefix sem_).
Most other routines return an error number if an error is encountered.
This discourages use of errno, which is non-reentrant
and inefficient in a multithreaded environment.
The Threads Library does not guarantee to preserve errno across calls.
Signal handling
UNIX System signals were designed for inter-process communication.
They have been enhanced to work with multithreaded programs,
but their use here should be restricted.
We recommend that only a limited number of threads within a process
access and receive signals.
These threads can convert the notification provided by signals
into internal communication between threads.
Each thread in a process has its own signal mask,
which is inherited from its creator thread.
If there is a signal handler in effect for any given
signal, it is shared by all the threads in the process.
Threads can use
pthread_sigmask(3pthread)
to modify their signal masks.
When a multithreaded process receives a signal,
the signal is delivered to one thread interested in the signal.
Threads express interest in a signal by calling
sigwait(2)
or by using
signal(2),
sigset [see
signal(2)],
or
sigaction(2)
to establish a handler for a signal.
Threads use
pthread_kill(3pthread)
to send a signal
to a sibling thread.
Thread-specific data
Thread-specific data routines provide a thread-safe alternative
to static or external data.
That is, they provide a way for threads to create and access private data
that persist across function calls.
The thread-specific data routines are:
pthread_getspecific(3pthread),
pthread_key_create(3pthread),
pthread_key_delete(3pthread),
and
pthread_setspecific(3pthread).
Synchronization
The synchronization interfaces allow coordination of threads
within a process as well as coordination of threads in different
processes.
The following synchronization mechanisms are described in this section:
-
mutual exclusion locks (mutex locks)
-
condition variables
-
semaphores
-
read-write locks
Most of these mechanisms can be initialized
to be of one of two types: PTHREAD_PROCESS_PRIVATE
or PTHREAD_PROCESS_SHARED.
PTHREAD_RPROCESS_PRIVATE mechanisms should be used
only by threads within the current process,
whether or not the synchronization objects are in shared memory.
PTHREAD_PROCESS_SHARED 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.
Mutual exclusion locks
A mutual exclusion lock, or ``mutex'',
is a synchronization mechanism
used to serialize the execution of threads.
Mutexes 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.
The type of mutex is contained in the type
attribute of the mutex attributes.
Valid mutex types include the following:
PTHREAD_MUTEX_NORMAL-
This type of mutex does not detect deadlock.
A thread attempting to relock this mutex
without first unlocking it will deadlock.
Attempting to unlock a mutex locked by a
different thread results in undefined behavior.
Attempting to unlock an unlocked mutex
results in undefined behavior.
PTHREAD_MUTEX_ERRORCHECK-
This type of mutex provides error checking.
A thread attempting to relock this mutex
without first unlocking it will return with
an error.
A thread attempting to unlock a mutex which
another thread has locked will return with
an error.
A thread attempting to unlock an unlocked
mutex will return with an error.
PTHREAD_MUTEX_RECURSIVE-
A thread attempting to relock this mutex
without first unlocking it will succeed
in locking the mutex.
The relocking deadlock which can occur
with mutexes of type PTHREAD_MUTEX_NORMAL
cannot occur with this type of mutex.
Multiple locks of this mutex require the same
number of unlocks to release the mutex before
another thread can acquire the mutex.
A thread attempting to unlock a mutex which
another thread has locked will return with
an error.
A thread attempting to unlock an unlocked
mutex will return with an error.
PTHREAD_MUTEX_DEFAULT-
This type of mutex behaves exactly as described for
PTHREAD_MUTEX_NORMAL, above.
See
pthread_mutex_destroy(3pthread),
pthread_mutexattr_init(3pthread),
pthread_mutexattr_setprotocol(3pthread),
pthread_mutexattr_setpshared(3pthread),
pthread_mutex_init(3pthread),
and
pthread_mutex_lock(3pthread)
for details.
Recursive mutex locks are variations of the mutex lock.
Condition variables
A condition and 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
pthread_condattr_destroy(3pthread),
pthread_condattr_init(3pthread),
pthread_condattr_getpshared(3pthread),
pthread_condattr_setpshared(3pthread),
pthread_cond_broadcast(3pthread),
pthread_cond_destroy(3pthread),
pthread_cond_init(3pthread),
pthread_cond_signal(3pthread),
pthread_cond_timedwait(3pthread),
and
pthread_cond_wait(3pthread).
Read-write locks
Read-write 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.
See
pthread_rwlock_rdlock(3pthread),
pthread_rwlock_tryrdlock(3pthread),
pthread_rwlock_trywrlock(3pthread),
pthread_rwlock_unlock(3pthread),
pthread_rwlock_wrlock(3pthread),
pthread_rwlock_destroy(3pthread),
and
pthread_rwlock_init(3pthread).
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 sem_init
to the number of free resources.
Threads then atomically increment the count with sem_post
when resources are released
and atomically decrement the count with sem_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 sem_wait
will block until the count becomes greater than zero.
See
sem_close(3pthread),
sem_destroy(3pthread),
sem_getvalue(3pthread),
sem_init(3pthread),
sem_open(3pthread),
sem_post(3pthread),
sem_unlink(3pthread),
sem_trywait(3pthread),
and
sem_wait(3pthread).
Thread cancellation
The thread cancellation mechanism allows a thread
to terminate the execution of any other thread
in the process in a controlled manner.
The target thread (that is, the one that is being canceled)
is allowed to hold cancellation requests pending in
a number of ways and to perform application-specific
cleanup processing when the notice of
cancellation is acted upon.
Cancellation is controlled by the cancellation control
interfaces.
Each thread maintains its own cancelability state.
Cancellation may only occur at cancellation points
or when the thread is asynchronously cancelable.
The thread cancellation mechanism described in
this section depends upon programs having set
deferred cancelability state,
which is specified as the default.
Applications must also carefully follow static
lexical scoping rules in their execution behavior.
For instance, use of setjmp,
return, goto, and so on, to
leave user-defined cancellation scopes
without doing the necessary scope pop
operation will result in undefined behavior.
Use of asynchronous cancelability while
holding resources which potentially need
to be released may result in resource loss.
Similarly, cancellation scopes may only
be safely manipulated (pushed and popped)
when the thread is in the deferred or
disabled cancelability states.
Cancelability States
The cancelability state of a thread
determines the action taken upon receipt of a
cancellation request.
The thread may control cancellation in a number of ways.
Each thread maintains its own cancelability state,
which may be encoded in two bits:
Cancelability Enable-
When cancelability is PTHREAD_CANCEL_DISABLE,
cancellation requests against the target thread
are held pending.
By default, cancelability is set to
PTHREAD_CANCEL_ENABLE.
Cancelability Type-
When cancelability is enabled and the
cancelability type is PTHREAD_CANCEL_ASYNCHRONOUS,
new or pending cancellation requests may be
acted upon at any time.
When cancelability is enabled and the cancelability
type is PTHREAD_CANCEL_DEFERRED,
cancellation requests are held pending until
a cancellation point (see below) is reached.
If cancelability is disabled,
the setting of the cancelability type has no
immediate effect as all cancellation requests
are held pending, however, once cancelability
is enabled again the new type will be in effect.
The cancelability type is PTHREAD_CANCEL_DEFERRED
in all newly created threads including the
thread in which main was first invoked.
Cancellation Points
Cancellation points occur when a thread
is executing the following functions:
pthread_cond_timedwait()
pthread_cond_wait()
pthread_join()
pthread_testcancel()
sem_wait()
sleep()
The side effects of acting upon a cancellation
request while suspended during a call of a
function is the same as the side effects that
may be seen in a single-threaded program when a
call to a function is interrupted by a signal and
the given function returns EINTR.
Any such side effects occur before any cancellation
cleanup handlers are called.
Whenever a thread has cancelability enabled
and a cancellation request has been made with
that thread as the target and the thread calls
pthread_testcancel, then the
cancellation request is acted upon before
pthread_testcancel returns.
If a thread has cancelability enabled
and the thread has an asynchronous cancellation
request pending and the thread is suspended at
a cancellation point waiting for an event
to occur, then the cancellation request
will be acted upon.
However, if the thread is suspended at a
cancellation point and the event that it is
waiting for occurs before the cancellation request
is acted upon, it is unspecified whether the
cancellation request is acted upon or whether the
request remains pending and the thread resumes normal execution.
Thread Cancellation Cleanup Handlers
Each thread maintains a list of
cancellation cleanup handlers.
The programmer uses the functions
pthread_cleanup_push and
pthread_cleanup_pop to place
routines on and remove routines from this list.
When a cancellation request is acted upon,
the routines in the list are invoked one
by one in LIFO sequence; that is, the last
routine pushed onto the list (Last In) is
the first to be invoked (First Out).
The thread invokes the cancellation cleanup
handler with cancellation disabled until
the last cancellation cleanup handler returns.
When the cancellation cleanup handler for
a scope is invoked, the storage for that scope
remains valid.
If the last cancellation cleanup handler returns, thread
execution is terminated and a
status of PTHREAD_CANCELED is made available
to any threads joining with the target.
The cancellation cleanup handlers are also
invoked when the thread calls pthread_exit(.
A side effect of acting upon a cancellation request
while in a condition variable wait is that the
mutex is reacquired before calling the first
cancellation cleanup handler.
In addition, the thread is no longer
considered to be waiting for the condition
and the thread will not have consumed
any pending condition signals on the condition.
A cancellation cleanup handler cannot
exit via longjmp or siglongjmp.
Async-Cancel Safety
The pthread_cancel, pthread_setcancelstate and
pthread_setcanceltype functions are defined
to be async-cancel safe.
No other functions in the Threads Library
are required to be async-cancel safe.
Supported Interfaces
Therefore, the following threads interfaces are supported:
POSIX Interfaces
pthread_atfork()
pthread_attr_destroy()
pthread_attr_getdetachstate()
pthread_attr_getschedparam()
pthread_attr_getstackaddr()
pthread_attr_getstacksize()
pthread_attr_init()
pthread_attr_setdetachstate()
pthread_attr_setschedparam()
pthread_attr_setstackaddr()
pthread_attr_setstacksize()
pthread_cancel()
pthread_cleanup_pop()
pthread_cleanup_push()
pthread_cond_broadcast()
pthread_cond_destroy()
pthread_cond_init()
pthread_cond_signal()
pthread_cond_timedwait()
pthread_cond_wait()
pthread_condattr_destroy()
pthread_condattr_getpshared()
pthread_condattr_init()
pthread_condattr_setpshared()
pthread_create()
pthread_detach()
pthread_equal()
pthread_exit()
pthread_getspecific()
pthread_join()
pthread_key_create()
pthread_key_delete()
pthread_kill()
pthread_mutex_destroy()
pthread_mutex_init()
pthread_mutex_lock()
pthread_mutex_trylock()
pthread_mutex_unlock()
pthread_mutexattr_destroy()
pthread_mutexattr_getpshared()
pthread_mutexattr_init()
pthread_mutexattr_setpshared()
pthread_once()
pthread_self()
pthread_setcancelstate()
pthread_setcanceltype()
pthread_setspecific()
pthread_sigmask()
pthread_testcancel()
sigwait()
X/Open Interfaces
pthread_getconcurrency()
pthread_mutexattr_gettype()
pthread_mutexattr_settype()
pthread_rwlock_destroy()
pthread_rwlock_init()
pthread_rwlock_rdlock()
pthread_rwlock_tryrdlock()
pthread_rwlock_trywrlock()
pthread_rwlock_unlock()
pthread_rwlock_wrlock()
pthread_rwlockattr_destroy()
pthread_rwlockattr_getpshared()
pthread_rwlockattr_init()
pthread_rwlockattr_setpshared()
pthread_setconcurrency()
On XSI-conformant systems,
_POSIX_THREAD_SAFE_FUNCTIONS is always
defined.
Therefore, the following interfaces are supported:
asctime_r()
ctime_r()
flockfile()
ftrylockfile()
funlockfile()
getc_unlocked()
getchar_unlocked()
getgrgid_r()
getgrnam_r()
getpwnam_r()
getpwuid_r()
gmtime_r()
localtime_r()
putc_unlocked()
putchar_unlocked()
rand_r()
readdir_r()
strtok_r()
The following threads interfaces are only supported on
XSI-conformant systems if the Realtime Threads
Feature Group is supported (see Realtime Threads):
pthread_attr_getinheritsched()
pthread_attr_getschedpolicy()
pthread_attr_getscope()
pthread_attr_setinheritsched()
pthread_attr_setschedpolicy()
pthread_attr_setscope()
pthread_getschedparam()
pthread_mutexattr_getprotocol()
pthread_mutexattr_setprotocol()
pthread_setschedparam()
Warnings
The Threads Library does not guarantee to preserve errno
across calls.
Additional sources of information
These books discuss the use of the
Threads library (3thread) and (3synch) and the Pthreads library
(3pthread), and provide code examples.
Refer to the manual pages provided
with the UnixWare operating system for specific
information about syntax and return values for
these interfaces.
-
THREADtime - The Multithreaded Programming Guide, Scott J. Norton
and Mark D. DiPasquale; 538 pages; Prentice Hall PTR;
1997; ISBN 0-13-190067-6
A complete guide to programming with POSIX threads,
this book describes various thread and process models, POSIX,
threads programming and debugging, and includes a good
introduction to threads, a chapter on debugging,
chapters on thread programming models and guidelines,
and the pthread manual pages.
-
Programming with POSIX Threads, David R. Butenhof; 381 pages;
Addison-Wesley professional computing series; 1997; ISBN 0-201-63392-2
A complete guide to programming
with POSIX threads,
this book introduces threads programming,
describes how to use the interfaces,
discusses the routines that can be called safely in a signal handler,
and explains what features are standard and what features
may vary from one implementation to another.
Code examples include some
which implement barriers and read/write locks (features
in the UnixWare threads library but not currently provided in POSIX).
-
Programming with Threads, Steve Kleiman, Devang Shah,
and Bart Smaalders; 534 pages; SunSoft Press, 1996; ISBN 0-13-172389-8
A complete reference for POSIX threads,
from introduction to advanced programming,
this book may be most useful to someone already
familiar with multithreaded programming
because the introductory topics are brief and
it concentrates on advanced topics.
UNIX International threads are listed in an appendix.
-
Threads Primer - A Guide to Multithreaded Programming, Bil Lewis
and Daniel Berg; 319 pages; SunSoft Press, 1996; ISBN 0-13-443698-9
A good introductory text for
someone unfamiliar with threads programming,
this book has code examples that use the UNIX International
threads (3thread) and (3synch) interfaces.
These are the only interfaces available in UnixWare prior to the
introduction of POSIX threads (3pthread) interfaces in Release 7.0.1.
POSIX thread interfaces are listed in an appendix.
References
_lwp_create(2),
exit(2),
pthread(4),
pthread_atfork(3pthread),
pthread_attr_getdetachstate(3pthread),
pthread_attr_getinheritsched(3pthread),
pthread_attr_getschedparam(3pthread),
pthread_attr_getschedpolicy(3pthread),
pthread_attr_getscope(3pthread),
pthread_attr_getstackaddr(3pthread),
pthread_attr_getstacksize(3pthread),
pthread_attr_setdetachstate(3pthread),
pthread_attr_setinheritsched(3pthread),
pthread_attr_setschedparam(3pthread),
pthread_attr_setschedpolicy(3pthread),
pthread_attr_setscope(3pthread),
pthread_attr_setstackaddr(3pthread),
pthread_attr_setstacksize(3pthread),
pthread_cancel(3pthread),
pthread_cleanup_pop(3pthread),
pthread_cleanup_push(3pthread),
pthread_cond_broadcast(3pthread),
pthread_cond_destroy(3pthread),
pthread_cond_init(3pthread),
pthread_cond_signal(3pthread),
pthread_cond_timedwait(3pthread),
pthread_cond_wait(3pthread).
pthread_condattr_destroy(3pthread),
pthread_condattr_getpshared(3pthread),
pthread_condattr_init(3pthread),
pthread_condattr_setpshared(3pthread),
pthread_create(3pthread),
pthread_detach(3pthread),
pthread_equal(3pthread),
pthread_exit(3pthread),
pthread_getconcurrency(3pthread),
pthread_getschedparam(3pthread),
pthread_getspecific(3pthread),
pthread_join(3pthread),
pthread_key_create(3pthread),
pthread_key_delete(3pthread),
pthread_kill(3pthread),
pthread_mutex_destroy(3pthread),
pthread_mutex_getprioceiling(3pthread),
pthread_mutex_init(3pthread),
pthread_mutex_lock(3pthread)
pthread_mutex_setprioceiling(3pthread),
pthread_mutex_trylock(3pthread),
pthread_mutex_unlock(3pthread),
pthread_mutexattr_destroy(3pthread),
pthread_mutexattr_getprioceiling(3pthread),
pthread_mutexattr_getprotocol(3pthread),
pthread_mutexattr_getpshared(3pthread),
pthread_mutexattr_gettype(3pthread),
pthread_mutexattr_init(3pthread),
pthread_mutexattr_setprioceiling(3pthread),
pthread_mutexattr_setprotocol(3pthread),
pthread_mutexattr_setpshared(3pthread),
pthread_mutexattr_settype(3pthread),
pthread_once(3pthread),
pthread_rwlock_destroy(3pthread),
pthread_rwlock_init(3pthread),
pthread_rwlock_rdlock(3pthread),
pthread_rwlock_tryrdlock(3pthread),
pthread_rwlock_trywrlock(3pthread),
pthread_rwlock_unlock(3pthread),
pthread_rwlock_wrlock(3pthread),
pthread_rwlockattr_destroy(3pthread),
pthread_rwlockattr_getpshared(3pthread),
pthread_rwlockattr_init(3pthread),
pthread_rwlockattr_setpshared(3pthread),
pthread_self(3pthread),
pthread_setcancelstate(3pthread),
pthread_setcanceltype(3pthread),
pthread_setconcurrency(3pthread),
pthread_setconcurrency(3pthread),
pthread_setschedparam(3pthread),
pthread_setspecific(3pthread),
pthread_sigmask(3pthread),
pthread_testcancel(3pthread),
sched(4),
sched_yield(3pthread),
sem_close(3pthread),
sem_destroy(3pthread),
sem_getvalue(3pthread),
sem_init(3pthread),
sem_open(3pthread),
sem_post(3pthread),
sem_trywait(3pthread),
sem_unlink(3pthread),
sem_wait(3pthread),
semaphore(4),
sigaction(2),
signal(2),
sigwait(2),
sigwait(3pthread)
Standards compliance
All of the provided interfaces, documented in the section (3pthread),
comply with The Single UNIX Specification, Version 2 provided
by The Open Group, with these exceptions:
-
support is not provided for threads in the classes SCHED_FIFO
and SCHED_RR
-
only the cancellation points listed above are supported.
© 2004 The SCO Group, Inc. All rights reserved.
UnixWare 7 Release 7.1.4 - 25 April 2004