Guide to DECthreads


Previous | Contents

When your program creates a thread object, mutex, or condition variable, it can accept the default attributes for that object or specify an existing attributes object that contains particular attribute values. For a thread object, you can change some of its attributes after execution of the corresponding thread has begun---for example, you can change the thread's priority.

To create an attributes object, you can use one of the following routines, depending on the type of object to which the attributes apply:

These routines create an attributes object containing default values for the individual attributes. To modify any attribute values in an attributes object, use one of the "attr_set" routines, such as pthread_attr_setinheritsched(), described in later sections.

Creating an attributes object (or changing the values in an attributes object) does not affect the attributes of existing thread objects, mutexes, and condition variables.

To destroy an attributes object, use one of the following routines:

Deleting an attributes object does not affect the attributes of objects previously created with that attributes object.

2.3 Thread Objects and Operations

Operations on threads take place with respect to a thread object. A thread object is a data structure maintained by DECthreads that contains the attribute information and DECthreads state information about a thread.

The following sections describe these operations on threads:

2.3.1 Creating and Starting a Thread

Creating a thread means directing DECthreads to create a thread object and to assign a unique thread identifier to the thread object. The thread object encapsulates attribute information about the thread and DECthreads' own state information about the thread. After a thread has been created, DECthreads has all the information it requires to start a distinct sequence of execution with this process.

Starting a thread means DECthreads causes a start routine, with its argument, to be called on some CPU within this system.

Your program creates a thread using the pthread_create() routine. This routine creates a thread object based on the settings of a specified thread attributes object, which your program must have previously created and initialized. Otherwise, without specifying a thread attributes object, you can create a new thread that has DECthreads default attributes.

DECthreads creates a thread in the ready state and prepares the thread to begin executing its start routine, the function passed to the pthread_create() routine. Depending on the presence of other threads and their scheduling and priority attributes, the new thread might start executing immediately. The new thread can also preempt its creator, depending on the two threads' respective scheduling and priority attributes. The caller of pthread_create() can synchronize with the new thread using the pthread_join() routine or using any mutually agreed upon mutexes or condition variables.

For the duration of the new thread's existence, DECthreads maintains and manages the thread object and other thread state overhead. A thread exists until it is both terminated and detached. (See Section 2.3.3 and Section 2.3.4 for more information about terminating and detaching threads.)

DECthreads assigns each new thread a thread identifier, which DECthreads writes into the address specified as the pthread_create() routine's thread argument. DECthreads writes the new thread's thread identifier before the new thread executes.

By default, the new thread's scheduling policy and priority are inherited from the creating thread---that is, by default, the pthread_create() routine ignores the scheduling policy and priority set in the specified thread attributes object. Thus, to create a thread that is subject to the scheduling policy and priority set in the specified thread attributes object, before calling pthread_create() your program must use the pthread_attr_setinheritsched() routine to set the inherit thread attributes object's scheduling attribute to PTHREAD_EXPLICIT_SCHED.

You can create a thread that is detached. To do so, create a thread using a thread attributes object whose detachstate attribute has been set, using the pthread_attr_setdetach() routine, to PTHREAD_CREATE_DETACHED. This is useful for creating a thread that your program knows will not join with any other thread. That is, when such a thread terminates, DECthreads automatically destroys the thread and its thread object.

For more detailed information about thread creation, see the reference description of the pthread_create() routine in Part 2.

2.3.2 Setting the Attributes of a New Thread

When creating a thread, your program can optionally specify the attributes of the new thread using a thread attributes object. To do so, your program must:

  1. Create a thread attributes object by calling the pthread_attr_init() routine.
  2. Set values for the individual attributes of the thread attributes object. (The POSIX.1c standard provides a separate routine for setting each attribute in the thread attributes object.)
  3. When ready to create the new thread, pass the address of the thread attributes object as an argument to the pthread_create() routine.

After your program creates a thread attributes object, that object can be reused for each new thread that the program creates. For the details about creating and deleting a thread attributes object, see the descriptions in Part 2 of the pthread_attr_create() and pthread_attr_delete() routines.

Using the thread attributes object, your program can specify these attributes of a new thread:

2.3.2.1 Setting the Inherit Scheduling Attribute

The inherit scheduling attribute's value specifies whether the new thread inherits the settings of its scheduling priority attribute and scheduling parameters attribute from the creating thread (the default behavior), or uses the scheduling attributes stored in the attributes object. Inheriting these settings from the creating thread is the default behavior, or you can specify the same by setting the thread attributes object's inherit scheduling attribute to PTHREAD_INHERIT_SCHED. To use the setting in the attributes objects, set the inherit scheduling attribute to PTHREAD_EXPLICIT_SCHED.

Use the pthread_attr_setinheritsched() routine to set the thread attributes object's inherit scheduling attribute.

2.3.2.2 Setting the Scheduling Policy Attribute

The scheduling policy attribute describes how DECthreads schedules the new thread for execution relative to the other threads in the process.

A thread has one of the following scheduling policies:

2.3.2.2.1 Techniques for Setting the Scheduling Policy Attribute

Use either of two techniques to set a thread attributes object's scheduling policy attribute:

Section 2.3.6 describes and shows the effect of the scheduling policy on thread scheduling.

2.3.2.2.2 Comparing Throughput and Real-Time Policies

The default throughput scheduling policy is intended to be an "adaptive" policy, giving each thread an opportunity to execute based on its behavior. That is, for a thread that doesn't execute often, DECthreads tends to give it high access to the processor because it isn't greatly affecting other threads. On the other hand, DECthreads tends to schedule with less preference any compute-bound threads with throughput scheduling policy.

This yields a responsive system in which all threads with throughput scheduling policy get a chance to run fairly frequently. It also has the effect of automatically resolving priority inversions, because over time any threads that have received less processing time (among those with throughput scheduling policy) will rise in preference while the running thread drops, and eventually the inversion is reversed.

The FIFO and RR scheduling policies are considered "real-time" policies, because they require DECthreads to schedule such threads strictly by the specified priority. Because threads that use real-time scheduling policies require additional DECthreads overhead, incautious use of the FIFO or RR policies can cause the performance of the application to suffer.

If relative priorities of threads are important to your application---that is, if a compute-bound thread really requires consistently predictable execution---then create those threads using either the FIFO or RR scheduling policy. However, use of "real-time" policies can expose the application to unexpected performance problems, such as priority inversions, and therefore their use should be avoided in most applications.

2.3.2.2.3 Portability of Scheduling Policy Settings

Only the SCHED_FIFO and SCHED_RR scheduling policies are portable across POSIX.1c-conformant implementations. The other scheduling policies are DECthreads extensions to the POSIX.1c standard.


Note

The SCHED_OTHER identifier is portable, but the POSIX.1c standard does not specify the behavior that it signifies. For example, on non-DECthreads platforms the SCHED_OTHER scheduling policy could be identical to the SCHED_FIFO or SCHED_RR policy.

2.3.2.3 Setting the Scheduling Parameters Attribute

The scheduling parameters attribute specifies the execution priority of a thread. (Although the terminology and format are designed to allow adding more scheduling parameters in the future, only priority is currently defined.) The priority is an integer value, but each policy can allow only a restricted range of priority values. You can determine the range for any policy by calling the sched_get_priority_min() or sched_get_priority_max() routines. DECthreads also supports a set of nonportable symbols designating the priority range for each policy, as follows:
Low High
PRI_FIFO_MIN PRI_FIFO_MAX
PRI_RR_MIN PRI_RR_MAX
PRI_OTHER_MIN PRI_OTHER_MAX
PRI_FG_MIN_NP PRI_FG_MAX_NP
PRI_BG_MIN_NP PRI_BG_MAX_NP

Section 2.3.6 describes how to specify a priority between the minimum and maximum values, and it also discusses how priority affects thread scheduling.

Use either of two techniques to set a thread attributes object's scheduling parameters attribute:

2.3.2.4 Setting the Stacksize Attribute

The stacksize attribute represents the minimum size (in bytes) of the memory required for a thread's stack. To increase or decrease the size of the stack for a new thread, call the pthread_attr_setstacksize() routine and use this thread attributes object when creating the thread and stack. You must specify at least PTHREAD_STACK_MIN bytes.

After a thread has been created, your program cannot change the size of the thread's stack. See Section 3.4.1 for more information about sizing a stack.

2.3.2.5 Setting the Stack Address Attribute

The stack address attribute represents the location or address of a region of memory that your program allocates to use as a thread's stack. The value of the stack address attribute represents the origin of the thread's stack. However, please be aware that the actual address you specify, relative to the stack memory you have allocated, is inherently nonportable.

To set the address of the stack origin for a new thread, call the
pthread_attr_setstackaddr() routine, specifying an initialized thread attributes object as an argument, and use the thread attributes object when creating the new thread. Use the pthread_attr_getstackaddr() routine to obtain the value of the stack address attribute of an initialized thread attributes object.

After a thread has been created, your program cannot change the address of the thread's stack.

You cannot create two concurrent threads that use the same stack address.

The system uses an unspecified (and varying) amount of the stack to "bootstrap" a newly created thread.

2.3.2.6 Setting the Guardsize Attribute

The guardsize attribute represents the minimum size (in bytes) of the guard area for the stack of a thread. A guard area can help a multithreaded program detect overflow of a thread's stack. A guard area is a region of no-access memory that DECthreads allocates at the overflow end of the thread's stack. When the thread attempts to access a memory location within this region, a memory addressing violation occurs.

A new thread can be created using a thread attributes object with a default guardsize attribute value. This value is platform dependent, but will always be at least one "hardware protection unit" (that is, at least one page; non-zero values are rounded up to the next integral page size). For more information, see this guide's platform-specfic appendixes.

DECthreads allows your program to specify the size of a thread stack guard area for two reasons:

To set the guardsize attribute of a thread attributes object, call the pthread_attr_setguardsize() routine. To obtain the value of the guardsize attribute in a thread attributes object, call the pthread_attr_getguardsize() routine.

The pthread_attr_setguardsize() and pthread_attr_getguardsize() routines replace (and are equivalent to) the pthread_attr_setguardsize_np() and pthread_attr_getguardsize_np() routines, respectively, that were available in previous DECthreads releases. The new routines provide a standardized and portable interface, specified by the Single UNIX Specification, Version 2; however, the older routines remain supported.

2.3.2.7 Setting the Contention Scope Attribute

When creating a thread, you can specify the set of threads with which this thread competes for processing resources. This set of threads is called the thread's contention scope.

A thread attributes object includes a contention scope attribute. The contention scope attribute specifies whether the new thread competes for processing resources only with other threads in its own process, called process contention scope, or with all threads on the system, called system contention scope.

Use the pthread_attr_setscope() routine to set an initialized thread attributes object's contention scope attribute. Use the pthread_attr_getscope() routine to obtain the value of the contention scope attribute of an initialized thread attributes object.

In the thread attributes object, set the contention scope attribute's value to PTHREAD_SCOPE_PROCESS to specify process contention scope, or set the value to PTHREAD_SCOPE_SYSTEM to specify system contention scope.

DECthreads selects at most one thread to execute on each processor at any point in time. DECthreads resolves the contention based on each thread's scheduling attributes (for example, priority) and scheduling policy (for example, round-robin).

A thread created using a thread attributes object whose contention scope attribute is set to PTHREAD_SCOPE_PROCESS contends for processing resources with other threads within its own process that also were created with PTHREAD_SCOPE_PROCESS. It is unspecified how such threads are scheduled relative to threads in other processes or threads in the same process that were created with PTHREAD_SCOPE_SYSTEM contention scope.

A thread created using a thread attributes object whose contention scope attribute is set to PTHREAD_SCOPE_SYSTEM contends for processing resources with other threads in any process that also were created with PTHREAD_SCOPE_SYSTEM.

Whether process contention scope and system contention scope are available for your program's threads depends on the host operating system. The following table summarizes DECthreads support for thread contention scope by operating system:

Operating System Available Thread Contention Scopes Default Thread
Contention Scope
DIGITAL UNIX Process
System
Process
OpenVMS Process Process
Windows NT System System


Note

On DIGITAL UNIX systems:

When a process contention scope thread creates a system contention scope thread that uses the default inheritance of scheduling attributes, the creation can fail with an [EPERM] error condition. This is because system contention scope threads can exceed "default" priority only if the process is running with root privileges.


2.3.3 Terminating a Thread

Terminating a thread means to cause a thread to end its execution. This can occur for any of the following reasons:

When a thread terminates, DECthreads performs these actions:

  1. DECthreads writes a return value (if one is available) into the terminated thread's thread object:
    Another thread can obtain this return value by joining with the terminated thread (using pthread_join()). See Section 2.3.5 for a description of joining with a thread.

    Note

    If the thread terminated by returning from its start routine normally and the start routine does not provide a return value, the results obtained by joining with that thread are unpredictable.

  2. If the termination results from a cancelation or a call to pthread_exit(), DECthreads calls, in turn, each cleanup handler that this thread declared (using pthread_cleanup_push()) and that is not yet removed (using pthread_cleanup_pop()). (DECthreads also transfers control to any appropriate CATCH, CATCH_ALL, or FINALLY blocks, as described in Chapter 5.)
    DECthreads calls the terminated thread's most recently pushed cleanup handler first. See Section 2.3.3.1 for more information about cleanup handlers.
    For C++ programmers: At normal exit from a thread, your program will call the appropriate destructor functions, just as if an exception had been raised.
  3. To exit the terminated thread due to a call to pthread_exit(), DECthreads raises the pthread_exit_e exception. To exit the terminated thread due to cancelation, DECthreads raises the pthread_cancel_e exception.
    Your program can use the DECthreads exception package to operate on the generated exception. (In particular, note that the practice of using CATCH handlers in place of pthread_cleanup_push() is not portable.) Chapter 5 describes the DECthreads exception package.
  4. For each of the terminated thread's thread-specific data keys that has a non-NULL value:
    DECthreads repeats this step until all thread-specific data values in the thread are NULL, or for up to a number of iterations equal to PTHREAD_DESTRUCTOR_ITERATIONS. This destroys all thread-specific data associated with the terminated thread. See Section 2.5 for more information about thread-specific data.
  5. DECthreads awakens the thread (if there is one) that is currently waiting to join with the terminated thread. That is, DECthreads awakens the thread that is waiting in a call to pthread_join().
  6. If the thread is already detached, DECthreads destroys its thread object. Otherwise, the thread continues to exist until detached or joined with. Section 2.3.4 describes detaching and destroying a thread.


    Previous | Next | Contents