Add Book to My BookshelfPurchase This Book Online

Chapter 1 - Why Threads

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

Terminating Thread Execution
A process terminates when it comes to the end of main. At that time the operating system reclaims the process's resources and stores its exit status. Similarly, a thread exits when it comes to the end of the routine in which it was started. (By the way, all threads expire when the process in which they run exits.) When a thread terminates, the Pthreads library reclaims any process or system resources the thread was using and stores its exit status. A thread can also explicitly exit with a call to pthread_exit. You can terminate another thread by calling pthread_cancel. In any of these cases, the Pthreads library runs any routines in its cleanup stack and any destructors in keys in which it has store values. We'll describe these features in Chapter 4, Managing Pthreads.
Exit Status and Return Values
The Pthreads library may or may not save the exit status of a thread when the thread exits, depending upon whether the thread is joinable or detached. A joinable thread, the default state of a thread at its creation, does have its exit status saved; a detached thread does not. Detaching a thread gives the library a break and lets it immediately reclaim the resources associated with the thread. Because the library will not have an exit status for a detached thread, you cannot use a pthread_join to join it. We'll show you how to dynamically set the state of a thread to detached in Chapter 2, Designing Threaded Programs, when we introduce the pthread_detach call. In Chapter 4, we'll show you how to create a thread in the detached state by specifying attribute objects.
What is the exit status of a thread? You can associate an exit status with a thread in either of two ways:
 If the thread terminates explicitly with a call to pthread_exit, the argument to the call becomes its exit status.
 If the thread does not call pthread_exit, the return value of the routine in which it started becomes its exit status.
As defined by the Pthreads standard, the thread-start routine (specified in the pthread_create call) returns a (void *) type. However, you'll often find that your thread-start routines must return something other than an address—e.g., a binary TRUE/FALSE indicator. They can do this quite easily as long as you remember to cast the return value as a (void *) type and avoid using a value that conflicts with PTHREAD_CANCELED, the only status value that the Pthreads library itself may return. (Pthreads implementations cannot define PTHREAD_CANCELED as a valid address or as NULL, so you're always safest when returning an address.) Of course, if the thread running the thread-start routine cannot be canceled (peek ahead to Chapter 4 to learn a bit about cancellation), you can ignore this restriction.
In Example 1-8, we've defined three possible exit status values and elected to have routine_x return pointers to integer constants with these values. We use pthread_exit and return interchangeably.
Example 1-8: Specifying a Thread's Exit Status (exit_status_alternative.c)
#include <stdio.h>
#include <pthread.h>
pthread_t thread;
static int arg;
static const int internal_error = -12;
static const int normal_error = -10;
static const int success = 1;
void * routine_x(void *arg_in)
{
  int *arg = (int *)arg_in;
  .
  .
  .
  if ( /* something that shouldn't have happened */) {
    pthread_exit((void *) &real_bad_error);
  }else if ( /* normal failure */ ) {
    return ((void *) &normal_error);
  }else {
    return ((void *) &success);
  }
}
extern int
main(int argc, char **argv)
{
  pthread_t thread;
  void *statusp;
  .
  .
  .
  pthread_create(&thread, NULL, routine_x, &arg);
  pthread_join(thread, &statusp);
  if (*statusp == PTHREAD_CANCELED) {
    printf("Thread was canceled.\n");
  }else {
    printf("Thread completed and exit status is %ld.\n", *(int *)statusp);
  }
return 0;
}
A final note on pthread_join is in order. Its purpose is to allow a single thread to wait on another's termination. The result of having multiple threads concurrently call pthread_join is undefined in the Pthreads standard.
Pthreads Library Calls and Errors
Most Pthreads library calls return zero on success and an error number otherwise.* Errors numbers are defined in the errno.h header file. The Pthreads standard doesn't require library calls to set errno, the global variable traditionally used by UNIX and POSIX.1 calls to deliver an error to their callers.
 *The two Pthreads library calls that don't return an error code upon failure are pthread_getspecific and pthread_self. A pthread_getspecific call returns NULL if it's unsuccessful. A pthread_self call always succeeds.</footnote>
You can use code similar to that in Example 1-9 to perform error checking on a Pthreads call.
Example 1-9: Full Error-Checking for a Pthreads Library Call
#include <errno.h>
#include <stdio.h>
.
.
.
if (rtn = pthread_create(...)) {
   /* error has occurred */
   fprintf(stderr,"Error: pthread_create, ");
   if (rtn == EAGAIN)
      fprintf(stderr,"Insufficent resources\n");
      else if (rtn == EINVAL)
              fprintf(stderr, "Invalid arguments\n");
   exit(1);
}
/* no error */
.
.
.
If your platform supports a routine to convert error numbers to a readable string such as the XPG4 call, strerror, your code could be simplified as in Example 1-10.
Example 1-10: Full Error-Checking for a Pthreads Library Call, Simplified
#include <string.h>
#include <stdio.h>
.
.
.
if (rtn = pthread_create(...))
   fprintf(stderr, "Error: pthread_create, %s\n", strerror(rtn)), exit(1);
/* no error */
.
.
.
In both examples, we made the rather typical decision to terminate the entire program rather than the individual thread that encountered the error (that is, we called exit rather than pthread_exit). What you do depends upon what your program is doing and what type of error it encounters.
As you may have noticed, we normally don't test the return values of the Pthreads library calls we make in the code examples in this book. We felt that doing so would get in the way of the threads programming practices the examples are meant to illustrate. If we were writing this code for a commercial product, we would diligently perform all required error checking.

Previous SectionNext Section
Books24x7.com, Inc © 2000 –  Feedback