1
0
Files
irix-657m-src/eoe/man/man5/pthreads.5
2022-09-29 17:59:04 +03:00

546 lines
17 KiB
Groff

'\"macro stdmacro
.\"
.\" ----------------
.TH pthreads 5
.\"
.\" ----------------
.SH NAME
pthreads
\- introduction to POSIX thread characteristics
.\"
.\" ----------------
.SH DESCRIPTION
This man page is intended as an overview of the POSIX thread model
as implemented in IRIX;
it is not an introduction to thread programming or a
detailed description of the IRIX implementation.
.PP
Thread programming is motivated by two concerns:
.\" ----------------
.TP 5
.B Application Performance
.PD 0
.RS
.IP \(bu 4
On a multiprocessor multiple threads may run at the same time.
.\"
.IP \(bu 4
Operations that cause the caller to wait do not prevent other
threads (in the same process) from making progress.
.RE
.PD
.\" ----------------
.TP
.B Programming Model
.PD 0
.RS
.IP \(bu 4
Complex applications can be structured more elegantly by partitioning
with threads.
.\"
.IP \(bu 4
Threads share many resources implicitly which can simplify co-operative
algorithms.
.RE
.PD
.\"
.PP
In the past a UNIX process has been thought of as having a single thread.
The POSIX thread programming model (known as
.IR pthreads )
introduces the concept of multiple threads within a single process.
A POSIX thread is an executable entity that belongs to a process.
It contains sufficient state to enable it to run on a processor
independently of its fellows.
In most other respects threads share state with their host process.
The vast majority of interfaces and features work
the same way in a multi-threaded process as an unthreaded one.
.PP
The POSIX threads API provides a set of interfaces and semantics
for creating and controlling threads.
Because the interfaces are defined by the ISO standards organisation
an application using them may enjoy the benefits of parallel programming
without sacrificing portability.
.\"
.\" ----------------
.SS Applications
To create a pthread process an application must be linked with the
pthread run-time library.
It is also recommended that the thread safe options be enabled at
compile time using the feature test macro,
.BR _POSIX_C_SOURCE .
.Ex
cc -D_POSIX_C_SOURCE=199506L app.c -llib0 -llib1 ... -lpthread
.Ee
See
.IR intro (3),
section 3P for further details.
.\"
.\" ----------------
.SS Components
POSIX threads introduces a number of thread components.
.\" ----------------
.TP 5
.B Attribute
An attribute is a characteristic of something that defines its behaviour.
Most of the objects introduced by pthreads have characteristics
which are set when it is created;
indeed some characteristics may only be set at that time.
A set of characteristics may be specified in an attribute object
which is passed to the creation interface.
An analogy is a mould or template that is used to shape
some artifact.
Every attribute has a default value and the attribute object itself
is optional.
.\" ----------------
.TP
.B Thread
A thread executes code.
It is created using
.IR pthread_create ()
and either inherits characteristics from its creator or has them
specified via creation attributes.
The
.IR pthread_attr_ *
interfaces may be used to create a thread attributes object.
.br
Many features of the process are shared by its threads, including
process and user ids (PID, UID), file descriptors,
memory (including text and data)
and signal handlers.
.br
Each thread has a unique identity which is used by a number of
pthread interfaces.
Thread ids may be compared using
.IR pthread_equal ().
.br
Threads terminate with an exit status [see
.IR pthread_exit ()].
By default the thread identity and exit status persist after the thread
has terminated until the status is retrieved using
.IR pthread_join ().
An application should either retrieve this status or arrange for
it to be automatically discarded on thread termination using
.IR pthread_detach ()
or setting the detach thread attribute.
.\" ----------------
.TP
.B Mutex Lock
A mutex lock facilitates exclusive access by a thread to a resource.
Only one thread may own a mutex at a time and is thus guaranteed
exclusive access.
.br
Mutex interfaces are described on the
.IR pthread_mutex_ *
man pages.
The
.IR pthread_mutexattr_ *
interfaces may be used to create a mutex attributes object.
Attributes include error checking, recursion and owner priority.
Mutexes are intended to be lightweight and only owned for
brief periods of time.
.\" ----------------
.TP
.B Condition Variable
A condition variable synchronises threads with an event of interest.
Condition variables allow a thread to wait for an event and be woken
up when the event occurs;
the nature of the event is determined by the application.
.br
Condition variable interfaces are described on the
.IR pthread_cond_ *
man pages.
The
.IR pthread_condattr_ *
interfaces may be used to create a condition variable attributes object.
.\" ----------------
.TP
.B Read-Write Lock
A read-write lock facilitates shared access for read and exclusive access for
write by threads to a resource.
They are used in conjunction with resources which are
frequently read but infrequently changed (written).
.br
Read-write lock interfaces are described on the
.IR pthread_rwlock_ *
man pages.
The
.IR pthread_rwlockattr_ *
interfaces may be used to create a read-write lock attributes object.
.\" ----------------
.TP
.B Semaphore
A semaphore synchronises threads with a counter.
Semaphores are not part of pthreads per se and do not have an
associated attributes object.
However anonymous semaphores provide a
.I pshared
flag (for semaphores which are private to the process) which
allows pthreads to optimise access [see
.IR sem_init (3C)].
Semaphore interfaces are described on the
.IR sem_ *
man pages.
.\"
.\" ----------------
.SS Semantics
POSIX threads introduces the following special semantics.
.\" ----------------
.TP 5
.B Cancellation
A cancellation request is a request for a thread to terminate.
Each thread specifies whether and when to act on cancellation requests
using its cancelability state and type.
A request is made with
.IR pthread_cancel ()
and the state and type are set with
.IR pthread_setcancelstate ()
and
.IR pthread_setcanceltype ().
Termination handlers may be established to execute code when a thread
terminates for some reason including acting on a cancellation request.
.\" ----------------
.TP
.B Signals
In the pthread signal model all threads share the signal disposition [see
.IR sigaction (2)]
but each thread has its own signal mask of blocked signals.
Signals may be sent to individual threads using the
.IR pthread_kill ()
interface.
Each thread may change its own mask using
.IR pthread_sigmask ().
In IRIX,
.IR sigprocmask (2)
is equivalent to
.IR pthread_sigmask ()
but a portable pthread application should only use the latter.
.br
A signal is delivered to at most one thread; it is not broadcast to all
threads.
.RS
.IP \(bu 4
When a signal is directed at a process the first eligible
thread is chosen to receive it.
An eligible thread is one that does not have the signal blocked in its
signal mask or is waiting in
.IR sigwait (3).
If there are no eligible threads then the signal remains pending
on the process until a thread becomes eligible.
This is called asynchronous signal delivery;
.IR kill (2)
causes this type of delivery.
.IP \(bu 4
When a signal is directed at a thread then that thread will receive it.
If the signal is blocked then it will remain pending on the target
thread; it will not be delivered to a different thread.
This is called synchronous signal delivery;
exceptions and program faults cause this type of delivery.
.IP \(bu 4
If the action of the signal is to stop, continue or terminate the
recipient then it will act on the process as a whole.
It is not possible to stop, continue or terminate a single
thread with a signal.
.RE
.\" ----------------
.TP
.B Notifications
An extension to signal handling for threads is the addition of
.B SIGEV_THREAD
which creates a thread instead of sending a signal as a means of
handling the occurrence of some event [see
.IR mq_notify (3C),
.IR aio_read (3)
and
.IR timer_create (3C)].
Creation of the thread takes place when the event occurs so
care should be taken to avoid any errors or else the notification may be lost.
.\" ----------------
.TP
.B Scheduling
When a processor executes instructions on behalf of a user it does so
according to a set of scheduling attributes
which are part of a kernel
.IR "execution vehicle" .
Every thread that executes on a processor or waits in the kernel
needs such a vehicle.
.IP
POSIX threads makes a distinction between system scope (kernel) scheduling
and process scope (run-time) scheduling.
In both scopes the individual thread scheduling policy and priority values
are set using the interfaces
.IR pthread_attr_setschedpolicy (),
.IR pthread_attr_setschedparam (),
and
.IR pthread_setschedparam ().
.br
Scope is defined when a thread is created using
.IR pthread_attr_setscope ():
.\" ----------------
.IP
.B system scope
threads are scheduled by the kernel;
the scheduling attributes of the thread and the kernel execution vehicle
are the same.
The kernel includes all system scope threads in its scheduling decisions.
These threads run at realtime policy and priority and may only be
created by privileged users.
.\" ----------------
.IP
.B process scope
threads are scheduled by the pthread run-time;
the scheduling attributes of the thread and the kernel execution vehicle
may be different.
The run-time makes scheduling decisions based only on the process scope
threads in the host process.
.IP
An advantage of system scope is that a thread can get
high performance and deterministic response.
A disadvantage is that kernel resources must be allocated to
each thread.
.IP
In contrast, process scope threads only require kernel state when
they are executing on a processor or waiting in the kernel.
The run-time scheduler multiplexes process scope threads onto a smaller
number of kernel execution vehicles.
This can produce faster scheduling because no kernel
state is involved.
.IP
The number of execution vehicles used for process scope threads
depends on application behaviour and system configuration.
By default, the run-time adjusts this number dynamically but the
.IR pthread_setconcurrency ()
interface gives a strong hint as to the desired value.
.\" ----------------
.IP
The execution vehicles used for process scope threads share
a set of kernel scheduling attributes which can
be changed using the
.IR sched_setscheduler ()
and
.IR sched_setparam ()
interfaces.
These interfaces do not affect system scope thread scheduling.
As with system scope threads changing these scheduling attributes
is a privileged operation.
.\" ----------------
.TP
.B Low-overhead Locking
In order to protect updates to internal pthread data structures, a
low-overhead locking mechanism is required.
This locking interface is not user-callable and is contained entirely
within the pthread library.
When pthreads are present, this locking mechanism is also used to ensure
that some routines in libc can be safely called from multiple threads.
Some examples of this are the
.IR stdio (3S)
routines and the
.IR malloc (3C)
routines.
.IP
By default, these locks spin/sleep for
.B process scope
threads on multiprocessor systems, and immediately block for
.B system scope
threads and on single processor systems.
In the spin/sleep lock path, the lock will be tried 1000 times, and then
.IR nanosleep (2)
will be called.
This process will be repeated until the lock can be obtained.
.IP
This process can be tuned for an individual application with the
.B PT_SPINS
environment variable.
This determines how many times the lock is tried before sleeping.
This environment variable is checked once at program startup time.
Different spin values may be used to improve application throughput;
however, higher values will probably increase user time while lower
values will probably increase system time.
In general, applications with more pthreads than processors will
probably benefit from setting
.B PT_SPINS
to a lower value, while applications with fewer pthreads may benefit
from setting the environment variable to a higher value.
If the environment variable is set to 0, these locks will all become
blocking locks.
.IR realtime (5)
applications and applications that create only
.B system scope
threads may benefit from setting
.B PT_SPINS
to 0.
This forces the locks to block immediately instead of having the lock
routine do a run-time check to determine if the caller is a
.B system scope
thread.
.\" ----------------
.TP
.B Thread Data
Pthreads share the address space; stacks, text and data are
accessible by all threads in the process.
This means that access to shared data is simpler than where multiple
processes use a shared memory region which each must map.
The cost is the potential for accidental corruption.
Individual thread data is provided using the notion of a shared
set of keys and unique thread values bound to each key.
The
.IR pthread_key_create ()
interface creates a new, shared key and
.IR pthread_setspecific ()
allows a thread to bind its own value to a key.
Conceptually, the key is an index to an array of values.
The same key used by different threads may retrieve a different values
because each thread has its own array.
.\" ----------------
.TP
.B Process Management
Some basic UNIX interfaces have particular semantics when
called from a POSIX threads process.
.\" ----------------
.IP
.B fork(2)
creates a new pthread process and follows the usual rules for
inherited state.
The new process has a single pthread (the one which made the call);
all other pthreads active prior to
.IR fork ()
are quietly destroyed
and their resources (stacks etc.) reclaimed by the pthread run-time.
A number of issues arise because
.IR fork ()
causes data to be copied from the parent to the child with no
synchronisation with threads that may be modifying that data.
To allow the application to perform its own synchronisation the
.IR pthread_atfork ()
interface can register handlers to be processed when
.IR fork ()
is used.
In general operations which are safe to perform
after a
.IR fork ()
are the same as those which are safe to perform in a signal handler.
.\" ----------------
.IP
.B exec(2)
overlays a new process image on the calling process;
all threads from the old image are destroyed.
Thread termination handlers and thread data destruction [see
.IR pthread_cleanup_push ()
and
.IR pthread_key_create ()]
are not performed.
The new process will only be a pthread process if the new image
is of a pthread process.
.\" ----------------
.IP
.B exit(2)
performs all the usual process clean up operations and then
destroys all threads in the process.
Thread termination handlers and thread data destruction [see
.IR pthread_cleanup_push ()
and
.IR pthread_key_create ()]
are not performed.
.\"
.\" ----------------
.SS Limitations
With POSIX threads there are some limitations and practices to avoid.
.\" ----------------
.TP
.B Not enough pthreads
Each pthread process has a resource limit called
.B RLIMIT_PTHREAD
on the number of threads it can create.
The value is inherited by child processes and may be set using
.IR setrlimit (2)
or the shell
.I limit
and
.I ulimit
commands.
The default limits can be changed using the
.IR systune (1M)
command on the
.I rlimit_pthread_cur
and
.I rlimit_pthread_max
variables.
.\" ----------------
.TP
.B Fatal exceptions
When a thread executes code in the pthread run-time scheduler it masks
signals so that signal handlers always run in a consistent environment.
A side effect of this is that if the thread raises an exception (for
example due to memory corruption) the kernel will terminate the process.
As an aid to debugging such problems the environment variable
.B PT_CORE
should be set prior to starting the application so that a core file
will be generated.
.\" ----------------
.TP
.B Stack overrun
Unlike the default stack in an unthreaded IRIX process, pthread stacks
are limited [see
.IR pthread_attr_setstacksize ()]
and a thread may overrun its stack.
By default pthread stacks have a protected region at the end of
the stack [see
.IR pthread_attr_setguardsize ()]
that can turn some of these overruns into a protection faults which is
generally preferable to overwriting data.
.\" ----------------
.TP
.B Dynamic loading
The pthread run-time relies on preempting some calls implemented by
the C run-time (libc).
This requirement means that the pthread DSO cannot safely be dynamically
loaded using
.IR dlopen (3C)
or
.IR sgidladd (3C).
.\" ----------------
.TP
.B Using sprocs
The
.IR sproc (2)
model of threading is incompatible with POSIX threads.
Attempts by an sproc process to create pthreads and vice-versa
will be rejected.
.\" ----------------
.TP
.B MAP_LOCAL memory
The POSIX thread memory model requires that memory be available to
all threads.
The
.B MAP_LOCAL
option to
.IR mmap (2)
is useful only to sproc processes and should not be used with pthreads.
.\" ----------------
.TP
.B Dynamic memory allocation
The
.IR sbrk (2)
call is not thread-safe.
It is used by the C run-time memory allocator,
.IR malloc (3C),
which is always used by the pthread run-time.
Safe use of
.IR sbrk (2)
outside of the run-time (for example by a third party memory allocator)
is not therefore possible.
.\"
.\" ----------------
.SS Documentation
Additional on-line documentation about pthreads is available in:
.PD 0
.IP
.I Topics in IRIX Programming: Chapter 13
.IP
.I SpeedShop User's Guide: Chapter 6
.PD
.\"
.\" ----------------
.SH "SEE ALSO"
pthread_*(3P)