Multithreaded Programming Guide

Attributes

Attributes are a way to specify behavior that is different from the default. When a thread is created with pthread_create(3T) or when a synchronization variable is initialized, an attribute object can be specified. The defaults are usually sufficient.


Note -

Attributes are specified only at thread creation time; they cannot be altered while the thread is being used.


An attribute object is opaque, and cannot be directly modified by assignments. A set of functions is provided to initialize, configure, and destroy each object type.

Once an attribute is initialized and configured, it has process-wide scope. The suggested method for using attributes is to configure all required state specifications at one time in the early stages of program execution. The appropriate attribute object can then be referred to as needed.

Using attribute objects has two primary advantages.

Attribute objects require attention at process exit time. When the object is initialized, memory is allocated for it. This memory must be returned to the system. The pthreads standard provides function calls to destroy attribute objects.

Initialize Attributes

pthread_attr_init(3T)

Use pthread_attr_init(3T) to initialize object attributes to their default values. The storage is allocated by the thread system during execution.

Prototype:

int pthread_attr_init(pthread_attr_t *tattr);
#include <pthread.h>

pthread_attr_t tattr;
int ret;

/* initialize an attribute to the default value */
ret = pthread_attr_init(&tattr);

The default values for attributes (tattr) are:

Table 3-1 Default Attribute Values for tattr

Attribute 

Value 

Result 

scope

PTHREAD_SCOPE_PROCESS

New thread is unbound - not permanently attached to LWP. 

detachstate

PTHREAD_CREATE_JOINABLE

Exit status and thread are preserved after the thread terminates.  

stackaddr

NULL

New thread has system-allocated stack address. 

stacksize

1 megabyte 

New thread has system-defined stack size. 

priority

 

New thread inherits parent thread priority. 

inheritsched

PTHREAD_INHERIT_SCHED

New thread inherits parent thread scheduling priority. 

schedpolicy

SCHED_OTHER

New thread uses Solaris-defined fixed priority scheduling; threads run until preempted by a higher-priority thread or until they block or yield. 

Return Values

Returns zero after completing successfully. Any other returned value indicates that an error occurred. If the following condition occurs, the function fails and returns the corresponding value.


ENOMEM

Returned when there is not enough memory to initialize the thread attributes object.

Destroy Attributes

pthread_attr_destroy(3T)

Use pthread_attr_destroy(3T) to remove the storage allocated during initialization. The attribute object becomes invalid.

Prototype:
int	pthread_attr_destroy(pthread_attr_t *tattr);
#include <pthread.h>

pthread_attr_t tattr;
int ret;

/* destroy an attribute */
ret = pthread_attr_destroy(&tattr); 

Return Values

pthread_attr_destroy() returns zero after completing successfully. Any other returned value indicates that an error occurred. If the following condition occurs, the function fails and returns the corresponding value.


EINVAL

Indicates that the value of tattr was not valid.

Set Detach State

pthread_attr_setdetachstate(3T)

When a thread is created detached (PTHREAD_CREATE_DETACHED), its thread ID and other resources can be reused as soon as the thread terminates. Use pthread_attr_setdetachstate(3T) when the calling thread does not want to wait for the thread to terminate.

When a thread is created nondetached (PTHREAD_CREATE_JOINABLE), it is assumed that you will be waiting for it. That is, it is assumed that you will be executing a pthread_join(3T)() on the thread.

Whether a thread is created detached or nondetached, the process does not exit until all threads have exited. See "Finishing Up"for a discussion of process termination caused by premature exit from main().

Prototype:

int	pthread_attr_setdetachstate(pthread_attr_t *tattr,int detachstate);
#include <pthread.h>

pthread_attr_t tattr;
int ret;

/* set the thread detach state */
ret = pthread_attr_setdetachstate(&tattr,PTHREAD_CREATE_DETACHED);

Note -

When there is no explicit synchronization to prevent it, a newly created, detached thread can die and have its thread ID reassigned to another new thread before its creator returns from pthread_create().


For nondetached (PTHREAD_CREATE_JOINABLE) threads, it is very important that some thread join with it after it terminates--otherwise the resources of that thread are not released for use by new threads. This commonly results in a memory leak. So when you do not want a thread to be joined, create it as a detached thread.


Example 3-1 Creating a Detached Thread

#include <pthread.h>

pthread_attr_t tattr;
pthread_t tid;
void *start_routine;
void arg
int ret;

/* initialized with default attributes */
ret = pthread_attr_init()(&tattr);
ret = pthread_attr_setdetachstate()(&tattr,PTHREAD_CREATE_DETACHED);
ret = pthread_create()(&tid, &tattr, start_routine, arg);

Return Values

pthread_attr_setdetachstate() returns zero after completing successfully. Any other returned value indicates that an error occurred. If the following condition occurs, the function fails and returns the corresponding value.


EINVAL

Indicates that the value of detachstate or tattr was not valid.

Get Detach State

pthread_attr_getdetachstate(3T)

Use pthread_attr_getdetachstate(3T) to retrieve the thread create state, which can be either detached or joined.

Prototype:

int	pthread_attr_getdetachstate(const pthread_attr_t *tattr,
    int *detachstate;
#include <pthread.h>

pthread_attr_t tattr;
int detachstate;
int ret;

/* get detachstate of thread */
ret = pthread_attr_getdetachstate (&tattr, &detachstate);

Return Values

pthread_attr_getdetachstate() returns zero after completing successfully. Any other returned value indicates that an error occurred. If the following condition occurs, the function fails and returns the corresponding value.


EINVAL

Indicates that the value of detachstate is NULL or tattr is invalid.

Set Stack Guard Size

pthread_attr_setguardsize(3T)

pthread_attr_setguardsize(3T) sets the guardsize of the attr object.

The guardsize argument provides protection against overflow of the stack pointer. If a thread's stack is created with guard protection, the implementation allocates extra memory at the overflow end of the stack as a buffer against stack overflow of the stack pointer. If an application overflows into this buffer an error results (possibly in a SIGSEGV signal being delivered to the thread).

The guardsize attribute is provided to the application for two reasons:

  1. Overflow protection can potentially result in wasted system resources. An application that creates a large number of threads, and knows its threads will never overflow their stack, can save system resources by turning off guard areas.

  2. When threads allocate large data structures on stack, a large guard area may be needed to detect stack overflow.

If guardsize is zero, a guard area will not be provided for threads created with attr. If guardsize is greater than zero, a guard area of at least size guardsize bytes is provided for each thread created with attr. By default, a thread has an implementation-defined, non-zero guard area.

A conforming implementation is permitted to round up the value contained in guardsize to a multiple of the configurable system variable PAGESIZE (see PAGESIZE in sys/mman.h). If an implementation rounds up the value of guardsize to a multiple of PAGESIZE, a call to pthread_attr_getguardsize() specifying attr will store, in guardsize, the guard size specified in the previous call to pthread_attr_setguardsize().

#include <pthread.h>

int pthread_attr_setguardsize(pthread_attr_t *attr, size_t  guardsize);

Return Value

pthread_attr_setguardsize() fails if:


EINVAL

The argument attr is invalid, the argument guardsize is invalid, or the argument guardsize contains an invalid value,.

Get Stack Guard Size

pthread_attr_getguardsize(3T)

pthread_attr_getguardsize(3T) gets the guardsize of the attr object.

A conforming implementation is permitted to round up the value contained in guardsize to a multiple of the configurable system variable PAGESIZE (see PAGESIZE in sys/mman.h). If an implementation rounds up the value of guardsize to a multiple of PAGESIZE, a call to pthread_attr_getguardsize() specifying attr will store, in guardsize, the guard size specified in the previous call to pthread_attr_setguardsize().

#include <pthread.h>

int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t  *guardsize);

Return Value

pthread_attr_getguardsize() fails if:


EINVAL

The argument attr is invalid, the argument guardsize is invalid, or the argument guardsize contains an invalid value,.

Set Scope

pthread_attr_setscope(3T)

Use pthread_attr_setscope(3T) to create a bound thread (PTHREAD_SCOPE_SYSTEM) or an unbound thread (PTHREAD_SCOPE_PROCESS).


Note -

Both thread types are accessible only within a given process.


Prototype:

int	pthread_attr_setscope(pthread_attr_t *tattr,int scope);
#include <pthread.h>

pthread_attr_t tattr;
int ret;

/* bound thread */
ret = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);

/* unbound thread */
ret = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_PROCESS);

Notice that there are three function calls in this example: one to initialize the attributes, one to set any variations from the default attributes, and one to create the pthreads.

#include <pthread.h>

pthread_attr_t attr;
pthread_t tid;
void start_routine;
void arg;
int ret;

/* initialized with default attributes */
ret = pthread_attr_init (&tattr);

/* BOUND behavior */
ret =  pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
ret = pthread_create (&tid, &tattr, start_routine, arg);

Return Values

pthread_attr_setscope() returns zero after completing successfully. Any other returned value indicates that an error occurred. If the following conditions occur, the function fails and returns the corresponding value.


EINVAL

An attempt was made to set tattr to a value that is not valid.

Get Scope

pthread_attr_getscope(3T)

Use pthread_attr_getscope(3T) to retrieve the thread scope, which indicates whether the thread is bound or unbound.

Prototype:

int	pthread_attr_getscope(pthread_attr_t *tattr, int *scope);
#include <pthread.h>

pthread_attr_t tattr;
int scope;
int ret;

/* get scope of thread */
ret = pthread_attr_getscope(&tattr, &scope);

Return Values

pthread_attr_getscope() returns zero after completing successfully. Any other returned value indicates that an error occurred. If the following condition occurs, the function fails and returns the corresponding value.


EINVAL

The value of scope is NULL or tattr is invalid.

Set Thread Concurrency Level

pthread_setconcurrency(3T)

Unbound threads in a process might or might not be required to be simultaneously active. By default, the threads implementation ensures that a sufficient number of threads are active so that the process can continue to make progress. While this conserves system resources, it might not produce the most effective level of concurrency.

pthread_setconcurrency(3T) allows an application to inform the threads implementation of its desired concurrency level, new_level. The actual level of concurrency provided by the implementation as a result of this function call is unspecified. (For Solaris threads, see "thr_setconcurrency(3T)".)

If new_level is zero, the implementation maintains the concurrency level at its discretion as if pthread_setconcurrency() was never called.

When an application calls pthread_setconcurrency(), it is informing the implementation of its desired concurrency level. The implementation uses this as a hint, not a requirement.

#include <pthread.h>

int pthread_setconcurrency(int new_level);

Return Value

pthread_setconcurrency() fails if:


EINVAL

The value specified by new_level is negative.


EAGAIN

The value specified by new_level would cause a system resource to be exceeded.

Get Thread Concurrency Level

pthread_getconcurrency(3T)

pthread_getconcurrency(3T) returns the value set by a previous call to pthread_setconcurrency(). If the pthread_setconcurrency() function was not previously called, pthread_getconcurrency() returns zero to indicate that the implementation is maintaining the concurrency level. (For Solaris threads, see "thr_getconcurrency(3T)".)

#include <pthread.h>

int pthread_getconcurrency(void);

Return Value

pthread_getconcurrency() always returns the concurrency level set by a previous call to pthread_setconcurrency(). If pthread_setconcurrency() has never been called, pthread_getconcurrency() returns zero.

Set Scheduling Policy

pthread_attr_setschedpolicy(3T)

Use pthread_attr_setschedpolicy(3T) to set the scheduling policy. The POSIX draft standard specifies scheduling policy attributes of SCHED_FIFO (first-in-first-out), SCHED_RR (round-robin), or SCHED_OTHER (an implementation-defined method).

SCHED_FIFO and SCHED_RR are optional in POSIX, and are supported for real time bound threads, only.

Currently, only the Solaris SCHED_OTHER, time-sharing, default value is supported in pthreads. For a discussion of scheduling, see the section "Scheduling".

Prototype:

int	pthread_attr_setschedpolicy(pthread_attr_t *tattr, int policy);
#include <pthread.h>

pthread_attr_t tattr;
int policy;
int ret;

/* set the scheduling policy to SCHED_OTHER */
ret = pthread_attr_setschedpolicy(&tattr, SCHED_OTHER);

Return Values

Returns zero after completing successfully. Any other returned value indicates that an error occurred. When either of the following conditions occurs, the function fails and returns the corresponding value.


EINVAL

An attempt was made to set tattr to a value that is not valid.


ENOTSUP

An attempt was made to set the attribute to an unsupported value.

Get Scheduling Policy

pthread_attr_getschedpolicy(3T)

Use pthread_attr_getschedpolicy(3T) to retrieve the scheduling policy. Currently, only the Solaris-based SCHED_OTHER default value is supported in pthreads.

Prototype:

int	pthread_attr_getschedpolicy(pthread_attr_t *tattr, int *policy);
#include <pthread.h>

pthread_attr_t tattr;
int policy;
int ret;

/* get scheduling policy of thread */
ret = pthread_attr_getschedpolicy (&tattr, &policy); 

Return Values

Returns zero after completing successfully. Any other returned value indicates that an error occurred. If the following condition occurs, the function fails and returns the corresponding value.


EINVAL

The parameter policy is NULL or tattr is invalid.

Set Inherited Scheduling Policy

pthread_attr_setinheritsched(3T)

Use pthread_attr_setinheritsched(3T) to set the inherited scheduling policy.

An inherit value of PTHREAD_INHERIT_SCHED (the default) means that the scheduling policies defined in the creating thread are to be used, and any scheduling attributes defined in the pthread_create() call are to be ignored. If PTHREAD_EXPLICIT_SCHED is used, the attributes from the pthread_create() call are to be used.

Prototype:

int	pthread_attr_setinheritsched(pthread_attr_t *tattr, int inherit);
#include <pthread.h>

pthread_attr_t tattr;
int inherit;
int ret;

/* use the current scheduling policy */
ret = pthread_attr_setinheritsched(&tattr, PTHREAD_EXPLICIT_SCHED);

Return Values

Returns zero after completing successfully. Any other returned value indicates that an error occurred. When either of the following conditions occurs, the function fails and returns the corresponding value.


EINVAL

An attempt was made to set tattr to a value that is not valid.


ENOTSUP

An attempt was made to set the attribute to an unsupported value.

Get Inherited Scheduling Policy

pthread_attr_getinheritsched(3T)

pthread_attr_getinheritsched(3T) returns the scheduling policy set by pthread_attr_setinheritsched().

Prototype:

int	pthread_attr_getinheritsched(pthread_attr_t *tattr, int *inherit);
#include <pthread.h>

pthread_attr_t tattr;
int inherit;
int ret;

/* get scheduling policy and priority of the creating thread */
ret = pthread_attr_getinheritsched (&tattr, &inherit); 

Return Values

Returns zero after completing successfully. Any other returned value indicates that an error occurred. If the following condition occurs, the function fails and returns the corresponding value.


EINVAL

The parameter inherit is NULL or tattr is invalid.

Set Scheduling Parameters

pthread_attr_setschedparam(3T)

pthread_attr_setschedparam(3T) sets the scheduling parameters.

Scheduling parameters are defined in the param structure; only priority is supported. Newly created threads run with this priority.

Prototype:

int	pthread_attr_setschedparam(pthread_attr_t *tattr,
    const struct sched_param *param);
#include <pthread.h>

pthread_attr_t tattr;
int newprio;
sched_param param;
newprio = 30;

/* set the priority; others are unchanged */
param.sched_priority = newprio;

/* set the new scheduling param */
ret = pthread_attr_setschedparam (&tattr, &param); 

Return Values

Returns zero after completing successfully. Any other returned value indicates that an error occurred. If the following conditions occur, the function fails and returns the corresponding value.


EINVAL

The value of param is NULL or tattr is invalid.

You can manage pthreads priority two ways. You can set the priority attribute before creating a child thread, or you can change the priority of the parent thread and then change it back.

Get Scheduling Parameters

pthread_attr_getschedparam(3T)

pthread_attr_getschedparam(3T) returns the scheduling parameters defined by pthread_attr_setschedparam().

Prototype:

int	pthread_attr_getschedparam(pthread_attr_t *tattr,
    const struct sched_param *param);
#include <pthread.h>

pthread_attr_t attr;
struct sched_param param;
int ret;

/* get the existing scheduling param */
ret = pthread_attr_getschedparam (&tattr, &param);

Return Values

pthread_attr_setschedparam() returns zero after completing successfully. Any other returned value indicates that an error occurred. If the following condition occurs, the function fails and returns the corresponding value.


EINVAL

The value of param is NULL or tattr is invalid.

Creating a Thread With a Specified Priority

You can set the priority attribute before creating the thread. The child thread is created with the new priority that is specified in the sched_param structure (this structure also contains other scheduling information).

It is always a good idea to get the existing parameters, change the priority, xxx the thread, and then reset the priority.

Example 3-2 shows an example of this.


Example 3-2 Creating a Prioritized Thread

#include <pthread.h>
#include <sched.h>

pthread_attr_t tattr;
pthread_t tid;
int ret;
int newprio = 20;
sched_param param;

/* initialized with default attributes */
ret = pthread_attr_init (&tattr);

/* safe to get existing scheduling param */
ret = pthread_attr_getschedparam (&tattr, &param);

/* set the priority; others are unchanged */
param.sched_priority = newprio;

/* setting the new scheduling param */
ret = pthread_attr_setschedparam (&tattr, &param);

/* with new priority specified */
ret = pthread_create (&tid, &tattr, func, arg); 

Set Stack Size

pthread_attr_setstacksize(3T)

pthread_attr_setstacksize(3T) sets the thread stack size.

The stacksize attribute defines the size of the stack (in bytes) that the system will allocate. The size should not be less than the system-defined minimum stack size. See "About Stacks"for more information.

Prototype:

int	pthread_attr_setstacksize(pthread_attr_t *tattr, int size);
#include <pthread.h>

pthread_attr_t tattr;
int size;
int ret;

size = (PTHREAD_STACK_MIN + 0x4000);

/* setting a new size */
ret = pthread_attr_setstacksize(&tattr, size);

In the example above, size contains the size, in number of bytes, for the stack that the new thread uses. If size is zero, a default size is used. In most cases, a zero value works best.

PTHREAD_STACK_MIN is the amount of stack space required to start a thread. This does not take into consideration the threads routine requirements that are needed to execute application code.

Return Values

Returns zero after completing successfully. Any other returned value indicates that an error occurred. If the following condition occurs, the function fails and returns the corresponding value.


EINVAL

The value returned is less than the value of PTHREAD_STACK_MIN, or exceeds a system-imposed limit, or tattr is not valid.

Get Stack Size

pthread_attr_getstacksize(3T)

pthread_attr_getstacksize(3T) returns the stack size set by pthread_attr_setstacksize().

Prototype:

int	pthread_attr_getstacksize(pthread_attr_t *tattr, size_t *size);
#include <pthread.h>

pthread_attr_t tattr;
int size;
int ret;

/* getting the stack size */
ret = pthread_attr_getstacksize(&tattr, &size);

Return Values

Returns zero after completing successfully. Any other returned value indicates that an error occurred. If the following condition occurs, the function fails and returns the corresponding value.


EINVAL

The value returned is less than the value of PTHREAD_STACK_MIN, or exceeds a system-imposed limit.

About Stacks

Typically, thread stacks begin on page boundaries and any specified size is rounded up to the next page boundary. A page with no access permission is appended to the top of the stack so that most stack overflows result in sending a SIGSEGV signal to the offending thread. Thread stacks allocated by the caller are used as is.

When a stack is specified, the thread should also be created PTHREAD_CREATE_JOINABLE. That stack cannot be freed until the pthread_join(3T) call for that thread has returned, because the thread's stack cannot be freed until the thread has terminated. The only reliable way to know if such a thread has terminated is through pthread_join(3T).

Generally, you do not need to allocate stack space for threads. The threads library allocates one megabyte of virtual memory for each thread's stack with no swap space reserved. (The library uses the MAP_NORESERVE option of mmap() to make the allocations.)

Each thread stack created by the threads library has a red zone. The library creates the red zone by appending a page to the top of a stack to catch stack overflows. This page is invalid and causes a memory fault if it is accessed. Red zones are appended to all automatically allocated stacks whether the size is specified by the application or the default size is used.


Note -

Because runtime stack requirements vary, you should be absolutely certain that the specified stack will satisfy the runtime requirements needed for library calls and dynamic linking.


There are very few occasions when it is appropriate to specify a stack, its size, or both. It is difficult even for an expert to know if the right size was specified. This is because even a program compliant with ABI standards cannot determine its stack size statically. Its size is dependent on the needs of the particular runtime environment in which it executes.

Building Your Own Stack

When you specify the size of a thread stack, be sure to account for the allocations needed by the invoked function and by each function called. The accounting should include calling sequence needs, local variables, and information structures.

Occasionally you want a stack that is a bit different from the default stack. An obvious situation is when the thread needs more than one megabyte of stack space. A less obvious situation is when the default stack is too large. You might be creating thousands of threads and not have enough virtual memory to handle the gigabytes of stack space that this many default stacks require.

The limits on the maximum size of a stack are often obvious, but what about the limits on its minimum size? There must be enough stack space to handle all of the stack frames that are pushed onto the stack, along with their local variables, and so on.

You can get the absolute minimum limit on stack size by calling the macro PTHREAD_STACK_MIN, which returns the amount of stack space required for a thread that executes a NULL procedure. Useful threads need more than this, so be very careful when reducing the stack size.

#include <pthread.h>

pthread_attr_t tattr;
pthread_t tid;
int ret;

int size = PTHREAD_STACK_MIN + 0x4000;

/* initialized with default attributes */
ret = pthread_attr_init(&tattr);

/* setting the size of the stack also */
ret = pthread_attr_setstacksize(&tattr, size);

/* only size specified in tattr*/
ret = pthread_create(&tid, &tattr, start_routine, arg); 

When you allocate your own stack, be sure to append a red zone to its end by calling mprotect(2).

Set Stack Address

pthread_attr_setstackaddr(3T)

pthread_attr_setstackaddr(3T) sets the thread stack address.

The stackaddr attribute defines the base of the thread's stack. If this is set to non-null (NULL is the default) the system initializes the stack at that address.

Prototype:

int	pthread_attr_setstackaddr(pthread_attr_t *tattr,void *stackaddr);
#include <pthread.h>

pthread_attr_t tattr;
void *base;
int ret;

base = (void *) malloc(PTHREAD_STACK_MIN + 0x4000);

/* setting a new address */
ret = pthread_attr_setstackaddr(&tattr, base);

In the example above, base contains the address for the stack that the new thread uses. If base is NULL, then pthread_create(3T) allocates a stack for the new thread with at least PTHREAD_STACK_MIN bytes.

Return Values

Returns zero after completing successfully. Any other returned value indicates that an error occurred. If the following condition occurs, the function fails and returns the corresponding value.


EINVAL

The value of base or tattr is incorrect.

This example shows how to create a thread with a custom stack address.

#include <pthread.h>

pthread_attr_t tattr;
pthread_t tid;
int ret;
void *stackbase;

stackbase = (void *) malloc(size);

/* initialized with default attributes */
ret = pthread_attr_init(&tattr);

/* setting the base address in the attribute */
ret = pthread_attr_setstackaddr(&tattr, stackbase);

/* only address specified in attribute tattr */
ret = pthread_create(&tid, &tattr, func, arg); 

This example shows how to create a thread with both a custom stack address and a custom stack size.

#include <pthread.h>

pthread_attr_t tattr;
pthread_t tid;
int ret;
void *stackbase;

int size = PTHREAD_STACK_MIN + 0x4000;
stackbase = (void *) malloc(size);

/* initialized with default attributes */
ret = pthread_attr_init(&tattr);

/* setting the size of the stack also */
ret = pthread_attr_setstacksize(&tattr, size);

/* setting the base address in the attribute */
ret = pthread_attr_setstackaddr(&tattr, stackbase);

/* address and size specified */
ret = pthread_create(&tid, &tattr, func, arg);

Get Stack Address

pthread_attr_getstackaddr(3T)

pthread_attr_getstackaddr(3T) returns the thread stack address set by pthread_attr_setstackaddr().

Prototype:

int	pthread_attr_getstackaddr(pthread_attr_t *tattr,void * *stackaddr);
#include <pthread.h>

pthread_attr_t tattr;
void *base;
int ret;

/* getting a new address */
ret = pthread_attr_getstackaddr (&tattr, *base); 

Return Values

Returns zero after completing successfully. Any other returned value indicates that an error occurred. If the following condition occurs, the function fails and returns the corresponding value.


EINVAL

The value or base or tattr is incorrect.