Skip to main content
Engineering LibreTexts

9.2: Creating threads

  • Page ID
    40761
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    The Pthread function that creates threads is called pthread_create. The following function shows how to use it:

    pthread_t make_thread(void *(*entry)(void *), Shared *shared)
    {
        int n;
        pthread_t thread;
    
        n = pthread_create(&thread, NULL, entry, (void *)shared);
        if (n != 0) {
            perror("pthread_create failed");
            exit(-1);
        }
        return thread;
    }
    

    make_thread is a wrapper I wrote to make pthread_create easier to use, and to provide error-checking.

    The return type from pthread_create is pthread_t, which you can think of as an id or “handle” for the new thread.

    If pthread_create succeeds, it returns 0 and make_thread returns the handle of the new thread. If an error occurs, pthread_create returns an error code and make_thread prints an error message and exits.

    The parameters of make_thread take some explaining. Starting with the second, Shared is a structure I defined to contain values shared between threads. The following typedef statement creates the new type:

    typedef struct {
        int counter;
    } Shared;
    

    In this case, the only shared variable is counter. make_shared allocates space for a Shared structure and initializes the contents:

    Shared *make_shared()
    {
        Shared *shared = check_malloc(sizeof (Shared));
        shared->counter = 0;
        return shared;
    }
    

    Now that we have a shared data structure, let’s get back to make_thread. The first parameter is a pointer to a function that takes a void pointer and returns a void pointer. If the syntax for declaring this type makes your eyes bleed, you are not alone. Anyway, the purpose of this parameter is to specify the function where the execution of the new thread will begin. By convention, this function is named entry:

    void *entry(void *arg)
    {
        Shared *shared = (Shared *) arg;
        child_code(shared);
        pthread_exit(NULL);
    }
    

    The parameter of entry has to be declared as a void pointer, but in this program we know that it is really a pointer to a Shared structure, so we can typecast it accordingly and then pass it along to child_code, which does the real work.

    As a simple example, child_code prints the value of the shared counter and increments it.

    void child_code(Shared *shared)
    {  
        printf("counter = %d\n", shared->counter);
        shared->counter++;
    }
    

    When child_code returns, entry invokes pthread_exit which can be used to pass a value to the thread that joins with this thread. In this case, the child has nothing to say, so we pass NULL.

    Finally, here is the code that creates the child threads:

        int i;
        pthread_t child[NUM_CHILDREN];
    
        Shared *shared = make_shared(1000000);
    
        for (i=0; i<NUM_CHILDREN; i++) {
            child[i] = make_thread(entry, shared);
        }
    

    NUM_CHILDREN is a compile-time constant that determines the number of child threads. child is an array of thread handles.


    This page titled 9.2: Creating threads is shared under a CC BY-NC license and was authored, remixed, and/or curated by Allen B. Downey (Green Tea Press) .

    • Was this article helpful?