Thread Creation

This lesson introduces you to the process of the creation of a thread.

We'll cover the following

The first thing you have to be able to do to write a multi-threaded program is to create new threads, and thus some kind of thread creation interface must exist. In POSIX, it is easy:

Press + to interact
#include <pthread.h>
int
pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void*),
void *arg);

Explanation

This declaration might look a little complex (particularly if you haven’t used function pointers in C), but actually it’s not too bad. There are four arguments:

  • thread
  • attr
  • start_routine
  • arg

The first, thread, is a pointer to a structure of type pthread_t; you’ll use this structure to interact with this thread, and thus you need to pass it to pthread_create() in order to initialize it.

The second argument, attr, is used to specify any attributes this thread might have. Some examples include setting the stack size or perhaps information about the scheduling priority of the thread. An attribute is initialized with a separate call to pthread_attr_init(); see the manual page for details. However, in most cases, the defaults will be fine; in this case, you will simply pass the value NULL in.

The third argument is the most complex, but is really just asking: which function should this thread start running in? In C, we call this a function pointer, and this one tells that the following is expected: a function name (start_routine), which is passed a single argument of type void * (as indicated in the parentheses after start_routine), and which returns a value of type void * (i.e., a void pointer).

If this routine instead required an integer argument, instead of a void pointer, the declaration would look like this:

Press + to interact
int pthread_create(..., // first two args are the same
void *(*start_routine)(int),
int arg);

If instead the routine took a void pointer as an argument but returned an integer, it would look like this:

Press + to interact
int pthread_create(..., // first two args are the same
int (*start_routine)(void *),
void *arg);

Finally, the fourth argument, arg, is exactly the argument to be passed to the function where the thread begins execution. You might ask: why are these void pointers needed? Well, the answer is quite simple: having a void pointer as an argument to the function start_routine allows you to pass in any type of argument; having it as a return value allows the thread to return any type of result.

An example

Let’s look at an example in the code snippet below. Here we just create a thread that is passed two arguments, packaged into a single type we define ourselves (myarg_t). The thread, once created, can simply cast its argument to the type it expects and thus unpack the arguments as desired.

#include <assert.h>
#include <stdio.h>
#include <pthread.h>

typedef struct {
  int a;
  int b;
} myarg_t;

void *mythread(void *arg) {
  myarg_t *args = (myarg_t *) arg;
  printf("%d %d\n", args->a, args->b);
  return NULL;
}

int main(int argc, char *argv[]) {
  pthread_t p;
  myarg_t args = { 10, 20};
  int rc = pthread_create(&p, NULL, mythread, &args);
  assert(rc == 0);
  (void) pthread_join(p, NULL);
  printf("done\n");
  return 0;
}
Creating a Thread

And there it is! Once you create a thread (mythread), you really have another live executing entity, complete with its own call stack, running within the same address space as all the currently existing threads in the program. The fun thus begins!

Get hands-on with 1400+ tech skills courses.