[ Team LiB ] Previous Section Next Section

26.2 Basic Thread Functions: Creation and Termination

In this section, we will cover five basic thread functions and then use these in the next two sections to recode our TCP client/server using threads instead of fork.

pthread_create Function

When a program is started by exec, a single thread is created, called the initial thread or main thread. Additional threads are created by pthread_create.

#include <pthread.h>

int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void *(*func) (void *), void *arg);

Returns: 0 if OK, positive Exxx value on error

Each thread within a process is identified by a thread ID, whose datatype is pthread_t (often an unsigned int). On successful creation of a new thread, its ID is returned through the pointer tid.

Each thread has numerous attributes: its priority, its initial stack size, whether it should be a daemon thread or not, and so on. When a thread is created, we can specify these attributes by initializing a pthread_attr_t variable that overrides the default. We normally take the default, in which case, we specify the attr argument as a null pointer.

Finally, when we create a thread, we specify a function for it to execute. The thread starts by calling this function and then terminates either explicitly (by calling pthread_exit) or implicitly (by letting the function return). The address of the function is specified as the func argument, and this function is called with a single pointer argument, arg. If we need multiple arguments to the function, we must package them into a structure and then pass the address of this structure as the single argument to the start function.

Notice the declarations of func and arg. The function takes one argument, a generic pointer (void *), and returns a generic pointer (void *). This lets us pass one pointer (to anything we want) to the thread, and lets the thread return one pointer (again, to anything we want).

The return value from the Pthread functions is normally 0 if successful or nonzero on an error. But unlike the socket functions, and most system calls, which return –1 on an error and set errno to a positive value, the Pthread functions return the positive error indication as the function's return value. For example, if pthread_create cannot create a new thread because of exceeding some system limit on the number of threads, the function return value is EAGAIN. The Pthread functions do not set errno. The convention of 0 for success or nonzero for an error is fine since all the Exxx values in <sys/errno.h> are positive. A value of 0 is never assigned to one of the Exxx names.

pthread_join Function

We can wait for a given thread to terminate by calling pthread_join. Comparing threads to Unix processes, pthread_create is similar to fork, and pthread_join is similar to waitpid.

#include <pthread.h>

int pthread_join (pthread_t tid, void ** status);

Returns: 0 if OK, positive Exxx value on error

We must specify the tid of the thread that we want to wait for. Unfortunately, there is no way to wait for any of our threads (similar to waitpid with a process ID argument of –1). We will return to this problem when we discuss Figure 26.14.

If the status pointer is non-null, the return value from the thread (a pointer to some object) is stored in the location pointed to by status.

pthread_self Function

Each thread has an ID that identifies it within a given process. The thread ID is returned by pthread_create and we saw it was used by pthread_join. A thread fetches this value for itself using pthread_self.

#include <pthread.h>

pthread_t pthread_self (void);

Returns: thread ID of calling thread

Comparing threads to Unix processes, pthread_self is similar to getpid.

pthread_detach Function

A thread is either joinable (the default) or detached. When a joinable thread terminates, its thread ID and exit status are retained until another thread calls pthread_join. But a detached thread is like a daemon process: When it terminates, all its resources are released and we cannot wait for it to terminate. If one thread needs to know when another thread terminates, it is best to leave the thread as joinable.

The pthread_detach function changes the specified thread so that it is detached.

#include <pthread.h>

int pthread_detach (pthread_t tid);

Returns: 0 if OK, positive Exxx value on error

This function is commonly called by the thread that wants to detach itself, as in


pthread_detach (pthread_self());



pthread_exit Function

One way for a thread to terminate is to call pthread_exit.

#include <pthread.h>

void pthread_exit (void *status);

Does not return to caller

If the thread is not detached, its thread ID and exit status are retained for a later pthread_join by some other thread in the calling process.

The pointer status must not point to an object that is local to the calling thread since that object disappears when the thread terminates.

There are two other ways for a thread to terminate:

  • The function that started the thread (the third argument to pthread_create) can return. Since this function must be declared as returning a void pointer, that return value is the exit status of the thread.

  • If the main function of the process returns or if any thread calls exit, the process terminates, including any threads.

    [ Team LiB ] Previous Section Next Section