DOC HOME SITE MAP MAN PAGES GNU INFO SEARCH PRINT BOOK
 

Intro(PTHREAD)


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(S)]. 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(PTHREAD).

A thread can also be bound to an LWP for its lifetime [see pthread_attr_setscope(PTHREAD)]. 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(PTHREAD) 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(PTHREAD) 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(S), threads create siblings for which they do not have to wait. Sibling threads can be awaited with pthread_join(PTHREAD) (see below), but this is optional.

Thread exit and process exit

pthread_exit(PTHREAD) causes the calling thread to terminate its execution.

A process containing threads will terminate in any of the following four circumstances:

Joining or waiting for a thread

A thread uses pthread_join(PTHREAD) 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(PTHREAD)), 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:

Multiplexed threads must run under the time-sharing policy. Bound threads can run under any of the policies. See pthread_attr_setschedpolicy(PTHREAD) or pthread_setschedparam(PTHREAD) for details.

A thread can set its scheduling policy and priority with pthread_setschedparam(PTHREAD). It can retrieve its scheduling policy and priority with pthread_getschedparam(PTHREAD). sched_yield(PTHREAD) 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(PTHREAD) 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(S) or by using signal(S), sigset [see signal(S)], or sigaction(S) to establish a handler for a signal.

Threads use pthread_kill(PTHREAD) 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(PTHREAD), pthread_key_create(PTHREAD), pthread_key_delete(PTHREAD), and pthread_setspecific(PTHREAD).

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:

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(PTHREAD), pthread_mutexattr_init(PTHREAD), pthread_mutexattr_setprotocol(PTHREAD), pthread_mutexattr_setpshared(PTHREAD), pthread_mutex_init(PTHREAD), and pthread_mutex_lock(PTHREAD) 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(PTHREAD), pthread_condattr_init(PTHREAD), pthread_condattr_getpshared(PTHREAD), pthread_condattr_setpshared(PTHREAD), pthread_cond_broadcast(PTHREAD), pthread_cond_destroy(PTHREAD), pthread_cond_init(PTHREAD), pthread_cond_signal(PTHREAD), pthread_cond_timedwait(PTHREAD), and pthread_cond_wait(PTHREAD).

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(PTHREAD), pthread_rwlock_tryrdlock(PTHREAD), pthread_rwlock_trywrlock(PTHREAD), pthread_rwlock_unlock(PTHREAD), pthread_rwlock_wrlock(PTHREAD), pthread_rwlock_destroy(PTHREAD), and pthread_rwlock_init(PTHREAD).

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(PTHREAD), sem_destroy(PTHREAD), sem_getvalue(PTHREAD), sem_init(PTHREAD), sem_open(PTHREAD), sem_post(PTHREAD), sem_unlink(PTHREAD), sem_trywait(PTHREAD), and sem_wait(PTHREAD).

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.

References

_lwp_create(S), exit(S), pthread(F), pthread_atfork(PTHREAD), pthread_attr_getdetachstate(PTHREAD), pthread_attr_getinheritsched(PTHREAD), pthread_attr_getschedparam(PTHREAD), pthread_attr_getschedpolicy(PTHREAD), pthread_attr_getscope(PTHREAD), pthread_attr_getstackaddr(PTHREAD), pthread_attr_getstacksize(PTHREAD), pthread_attr_setdetachstate(PTHREAD), pthread_attr_setinheritsched(PTHREAD), pthread_attr_setschedparam(PTHREAD), pthread_attr_setschedpolicy(PTHREAD), pthread_attr_setscope(PTHREAD), pthread_attr_setstackaddr(PTHREAD), pthread_attr_setstacksize(PTHREAD), pthread_cancel(PTHREAD), pthread_cleanup_pop(PTHREAD), pthread_cleanup_push(PTHREAD), pthread_cond_broadcast(PTHREAD), pthread_cond_destroy(PTHREAD), pthread_cond_init(PTHREAD), pthread_cond_signal(PTHREAD), pthread_cond_timedwait(PTHREAD), pthread_cond_wait(PTHREAD). pthread_condattr_destroy(PTHREAD), pthread_condattr_getpshared(PTHREAD), pthread_condattr_init(PTHREAD), pthread_condattr_setpshared(PTHREAD), pthread_create(PTHREAD), pthread_detach(PTHREAD), pthread_equal(PTHREAD), pthread_exit(PTHREAD), pthread_getconcurrency(PTHREAD), pthread_getschedparam(PTHREAD), pthread_getspecific(PTHREAD), pthread_join(PTHREAD), pthread_key_create(PTHREAD), pthread_key_delete(PTHREAD), pthread_kill(PTHREAD), pthread_mutex_destroy(PTHREAD), pthread_mutex_getprioceiling(PTHREAD), pthread_mutex_init(PTHREAD), pthread_mutex_lock(PTHREAD) pthread_mutex_setprioceiling(PTHREAD), pthread_mutex_trylock(PTHREAD), pthread_mutex_unlock(PTHREAD), pthread_mutexattr_destroy(PTHREAD), pthread_mutexattr_getprioceiling(PTHREAD), pthread_mutexattr_getprotocol(PTHREAD), pthread_mutexattr_getpshared(PTHREAD), pthread_mutexattr_gettype(PTHREAD), pthread_mutexattr_init(PTHREAD), pthread_mutexattr_setprioceiling(PTHREAD), pthread_mutexattr_setprotocol(PTHREAD), pthread_mutexattr_setpshared(PTHREAD), pthread_mutexattr_settype(PTHREAD), pthread_once(PTHREAD), pthread_rwlock_destroy(PTHREAD), pthread_rwlock_init(PTHREAD), pthread_rwlock_rdlock(PTHREAD), pthread_rwlock_tryrdlock(PTHREAD), pthread_rwlock_trywrlock(PTHREAD), pthread_rwlock_unlock(PTHREAD), pthread_rwlock_wrlock(PTHREAD), pthread_rwlockattr_destroy(PTHREAD), pthread_rwlockattr_getpshared(PTHREAD), pthread_rwlockattr_init(PTHREAD), pthread_rwlockattr_setpshared(PTHREAD), pthread_self(PTHREAD), pthread_setcancelstate(PTHREAD), pthread_setcanceltype(PTHREAD), pthread_setconcurrency(PTHREAD), pthread_setconcurrency(PTHREAD), pthread_setschedparam(PTHREAD), pthread_setspecific(PTHREAD), pthread_sigmask(PTHREAD), pthread_testcancel(PTHREAD), sched(F), sched_yield(PTHREAD), sem_close(PTHREAD), sem_destroy(PTHREAD), sem_getvalue(PTHREAD), sem_init(PTHREAD), sem_open(PTHREAD), sem_post(PTHREAD), sem_trywait(PTHREAD), sem_unlink(PTHREAD), sem_wait(PTHREAD), semaphore(F), sigaction(S), signal(S), sigwait(S), sigwait(PTHREAD)

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:
© 2005 The SCO Group, Inc. All rights reserved.
SCO OpenServer Release 6.0.0 - 01 June 2005