If you are used to the process model (fork, waitpid, exit), you will find these functions have direct parallels, but with slightly different syntax and behaviors.

1. Creating a Thread: pthread_create

This is the engine starter. When your program starts, it has one thread (the “main” thread). To make more, you call this function.

int pthread_create(pthread_t *tid, const pthread_attr_t *attr,
                   void *(*func)(void *), void *arg);
  • tid: A pointer to where the system will write the new Thread ID.
  • attr: Attributes (like priority or stack size). We usually pass NULL to get the defaults.
  • func: The function the thread should run. It must take a void * argument and return a void *.
  • arg: The single argument passed to func.

Key Difference from fork():

  • fork() returns twice (once to parent, once to child). pthread_create() returns once (only to the creator).
  • Error Handling: Unlike most Unix functions that return -1 and set the global errno variable, Pthread functions return the error code directly (e.g., they return EAGAIN instead of 0). They do not set errno.
2. Waiting for a Thread: pthread_join

This is the thread equivalent of waitpid.

int pthread_join(pthread_t tid, void **status);
  • Purpose: It blocks the calling thread until the thread specified by tid terminates.
  • status: If not NULL, this pointer receives the exit value returned by the finished thread.
  • Limitation: Unlike waitpid, which can wait for any child (using -1), pthread_join must wait for a specific thread ID. You cannot wait for “the next available thread.”
3. Getting Your Own ID: pthread_self

This is the equivalent of getpid().

pthread_t pthread_self(void);

It allows a thread to find out its own ID, which is useful if it needs to detach itself or change its own attributes.

4. Detaching a Thread: pthread_detach

This concept is unique to threads.

  • Joinable (Default): When a standard thread exits, it hangs around as a “zombie” (holding onto its exit status and thread ID) until another thread calls pthread_join on it (to read the exit status or its return value). This does not mean attachable.
  • Detached: A detached thread disappears immediately when it finishes. Its resources are cleaned up automatically. You cannot call pthread_join on a detached thread.
int pthread_detach(pthread_t tid);

Common Usage: In network servers, we often create a thread for a client and then immediately call pthread_detach(pthread_self()) inside that thread. This means the main server thread doesn’t have to worry about cleaning up after the client thread finishes.

5. Terminating: pthread_exit

This is the equivalent of exit.

void pthread_exit(void *status);

Warning: The status pointer you pass here must point to global or heap memory (malloc’d). If you pass a pointer to a local variable on your stack, that variable will vanish when the thread exits, and the thread joining you will receive a pointer to garbage.