Multiple Thread Mania

In last week’s Lesson, a program spawned a single thread. This thread runs at the same time as the main program, interrupting text input (if you let it). Such fun! But a multithreaded program isn’t limited to running just two threads. Your code can spawn multiple threads, each running simultaneously.

The following code is based on the example from last week’s Lesson. But unlike that example, this code calls the thread_funct() function twice. I’ve modified the function so that it accepts an argument, which sets the character output.

2022_06_04-Lesson-a.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

void *thread_funct(void *a)
{
    const int loop=8;
    int x;

    for( x=0; x<loop; x++ )
    {
        printf("%s\n",(char *)a);
        sleep(1);
    }

    return(NULL);
}

int main()
{
    char buffer[BUFSIZ];
    int r;
    pthread_t thd1,thd2;

    /* spawn the thread 1 */
    r = pthread_create( &thd1, NULL, thread_funct, "*");
    if( r!=0 )
    {
        perror("Thread");
        exit(1);
    }
    
    /* spawn the thread 2 */
    r = pthread_create( &thd2, NULL, thread_funct, "#");
    if( r!=0 )
    {
        perror("Thread");
        exit(1);
    }
    
    /* prompt for your name */
    printf("What is your name? ");
    fgets(buffer,BUFSIZ,stdin);
    printf("Hello, %s",buffer);

    return(0);
}

Line 27 spawns the first thread, calling the thread_funct() function with "*" as its argument.

Line 35 spawns the second thread, with "#" as the thread function’s argument.

The result is that two characters appear as you attempt to type your name:

What is your name? #
*
#
*
Da#
*
n #
*
Gook#
*
in#
*

Hello, Dan Gookin

Both threads continue to run until they quit or you finish typing your name and the program quits.

A thread need not run simultaneously, however, You can also direct the code to wait for a thread to finish. To handle this job, use the thread_join() function. Here’s its format:

int pthread_join(pthread_t thread, void **value_ptr);

The first argument is a pthread_t value representing a running thread. The second argument represents a return value received from the function, NULL to ignore the value or when nothing is returned.

As with the pthread_create() function, zero is returned upon success. The global errno value is set upon failure. (Don’t rely on -1 as an error return value.)

The following code runs two threads, one that’s spawned from the thread_funct() and the main() function. When the pthread_join() function is called at Line 35, the main() function suspends execution until the thread_funct() thread runs its course.

2022_06_04-Lesson-b.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

void *thread_funct(void *a)
{
    const int loop=8;
    int x;

    for( x=0; x<loop; x++ )
    {
        printf("*\n");
        sleep(1);
    }

    return(NULL);
}

int main()
{
    char buffer[BUFSIZ];
    int r;
    pthread_t thd;

    /* spawn the new thread */
    r = pthread_create( &thd, NULL, thread_funct, NULL);
    if( r!=0 )
    {
        perror("Thread");
        exit(1);
    }
    
    /* wait for the thread */
    r = pthread_join( thd, NULL );
    if( r!=0 )
    {
        perror("Thread join");
        exit(1);
    }

    /* prompt for your name */
    printf("What is your name? ");
    fgets(buffer,BUFSIZ,stdin);

    return(0);
}

Because the pthread_join() function is called right away, the spawned thread runs to completion. After the thread is done, the program then prompts for the user’s name:

*
*
*
*
*
*
*
*
What is your name? Dan Gookin
Hello, Dan Gookin

Of course, the program runs the same as if the thread_funct() was just called and not spawned as a second thread. Still, this technique is how you can cause one thread to wait for another to finish its run.

The pthread_join() function can also be used to capture a return value from a thread. This operation can be a bit tricky! I cover it in next week’s Lesson.

Leave a Reply