Add Book to My BookshelfPurchase This Book Online

Chapter 4 - Managing Pthreads

Pthreads Programming
Bradford Nichols, Dick Buttlar and Jacqueline Proulx Farrell
 Copyright 1996 O'Reilly & Associates, Inc.

Setting Thread Attributes
Threads have certain properties, called attributes, that you can request through the Pthreads library. The Pthreads standard defines attributes that determine the following thread characteristics:
 Whether the thread is detached or joinable.  All Pthreads implementations provide this attribute.
 Size of the thread's private stack. An implementation provides this attribute if the _POSIX_THREAD_ATTR_STACKSIZE compile-time constant is defined.
 Location of the thread's stack. An implementation provides this attribute if the _POSIX_THREAD_ATTR_STACKADDR compile-time constant is defined.
 A thread's scheduling policy (and other attributes that determine how it may be scheduled). An implementation provides these attributes if the _POSIX_THREAD_ATTR_PRIORITY_SCHEDULING compile-time constant is defined.
Vendors often define custom attributes as a way of including extensions to the standard in their implementations.
As we've mentioned before, a thread is created with a set of default attributes. Because the threads we've been using in our examples thus far are threads of the gray flannel variety, we've accepted the defaults by passing NULL as an attribute parameter to the pthread_create call. To set a thread's attributes to something other than the default, we'd perform the following steps:
 1.Define an attribute object of type pthread_attr_t.
 2.Call pthread_attr_init to declare and initialize the attribute object.
 3.Make calls to specific Pthreads functions to set individual attributes in the object.
 4.Specify the fully initialized attribute object to the pthread_create call that creates the thread.
We'll walk through some specific examples of setting a thread's stack size, stack location, and detached state in the next few sections. We'll investigate the thread-scheduling attributes later in this chapter.
Setting a Thread's Stack Size
A thread uses its private stack to store local variables for each routine it has called (but not yet exited) up to its current point of execution.(It also leaves various pieces of procedure context information on the stack, like bread crumbs, so that it can find its way back to the previously executing routine when it exits the current one.) For instance, consider a worker thread in our ATM server. It calls process_request, does some processing, and pushes some of process_request's local variables on the stack. It then calls deposit, pushing some information that allows it to return to the next instruction in process_request when it exits deposit. Now, it pushes deposit's local variables on its stack. Suppose it then calls retrieve_account, and then some number-crunching routine, and then, and then....We'd certainly like our thread to have ample stack space for all routines in its current call chain.
Two factors can affect whether a thread will have enough room on its stack:
 The size of the local variables to each routine
 The number of routines that may be in its call chain at any one time
If our worker thread begins to call routines that locally declare kilobyte-sized buffers, we might have a problem. If it makes nested procedure calls to some pretty hefty libraries (like a Kerberos security library or an X graphics library), we'd better start stretching its stack.
Even nonthreaded processes run out of stack space from time to time. However, an individual thread's stack is much smaller than that devoted to an entire process. The space for the stacks of all threads in a process is carved out of the memory previously allocated for the stack of the process as a whole. As shown in Figure 4-1, a process stack normally starts in high memory and works its way down in memory without anything in its way until it reaches 0. For a process with individual threads, one thread's stack is bounded by the start of the next thread's stack, even if the next thread isn't using all of its stack space.
Figure 4-1: Process and thread stacks
To set a thread's stack size, we call pthread_attr_init to declare and initialize a custom thread attribute object (pthread_attr_t) in Example 4-1.
Example 4-1: Declaring a Custom Attribute (mattr.c)
#define MIN_REQ_SSIZE 81920
size_t default_stack_size;
pthread_attr_t stack_size_custom_attr;
Now that we've created and initialized our attribute object, we can set and check the value of any attribute in it, using the appropriate Pthreads function. In Example 4-2, we'll read and adjust the thread's stack size by calling pthread_attr_getstacksize and pthread_attr_setstacksize. The minimum stack size on the platform is always stored in PTHREAD_STACK_MIN and can be used to determine at run time if the default stack will be big enough.
Example 4-2: Checking and Setting Stack Size (mattr.c)
if (default_stack_size < MIN_REQ_SSIZE) {;
In Example 4-3, we'll create a thread that has the desired attribute (a MIN_REQ_SSIZE stack) by specifying the attribute object in a pthread_create call.
Example 4-3: Using an Attribute Object in pthread_create (mattr.c)
                (void *) mult_worker,
                (void *) p);
Take special notice that fiddling with a thread's stack is inherently nonportable. Stack size and location are platform-dependent; the bytes and bounds of your threads' stacks on Platform A may not quite match those of the stacks on Platform B.
Setting a Thread's Detached State
Detaching from a thread informs the Pthreads library that no other thread will use the pthread_join mechanism to synchronize with the thread's exiting. Because the library doesn't preserve the exit status of a detached thread, it can operate more efficiently and make the library resources that were associated with a thread available for reuse more quickly. If no other thread cares when a particular thread in your program exits, consider detaching that thread.
Back in Chapter 2, Designing Threaded Programs, we discussed how to use the pthread_detach function to dynamically place a joinable thread into a detached state. In Example 4-4, we'll show you how to do it with an attribute object at thread creation.
Example 4-4: Setting the Detached State in an Attribute Object (mattr.c)
pthread_attr_t detached_attr;
       pthread_attr_setdetachedstate(&detached_attr, PTHREAD_CREATE_DETACHED);
       pthread_create(&thread, &detached_attr, ...);
The pthread_attr_setdetachedstate function sets the detached state in an attribute object to either the PTHREAD_CREATE_DETACHED constant (detached)or the PTHREAD_CREATE_ JOINABLE constant (joinable). The pthread_attr_getdetachedstate function returns the current detached setting of a thread attribute object.
Setting Multiple Attributes
You can set multiple individual attributes within a single attribute object. In the next example, Example 4-5, we'll use calls to the pthread_attr_setstacksize function and the pthread_attr_setdetachedstate function to set a thread's stack size and detached state in the same object.
Example 4-5: Setting Multiple Attributes in an Attribute Object (mattr.c)
pthread_attr_t custom_attr;
       pthread_attr_setstacksize(&custom_attr, MIN_REQ_SSIZE);
       pthread_attr_setdetachedstate(&custom_attr, PTHREAD_CREATE_DETACHED);
       pthread_create(&thread, &custom_attr, ...);
Destroying a Thread Attribute Object
Throughout this section, we've declared and initialized thread attribute objects using the pthread_attr_init call. When we're finished using a thread attribute object, we can call pthread_attr_destroy to destroy it. Note that existing threads that were created using this object are not affected when the object is destroyed.

Previous SectionNext Section, Inc 2000   Feedback