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 鈥? 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 鈥?). 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.
|