Here a Thread, There a Thread

Better than forking — especially grandchild forking — is to use threads. These program chunks are more manageable than forking and they don’t recreate the entire program (process). Still, threads aren’t without their quirks. Further, they’re available only to the POSIX standard. Sorry, Windows.

To deal with threads, your code must include the pthread.h header file where the pthread_ family of functions are prototyped. Further, you must link in the pthread library to build the code. In Linux, add the -lpthread switch at build time. In macOS, the pthread library appears to be part of the standard C library.

At the simplest level, your code can set a function to run as its own thread. This function runs independently from the rest of the code. It’s best that the function use only local variables, which avoids several problems I won’t get into right now. Use the pthread_create() function to launch the new thread. Here’s the visually intimidating format:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);

The first argument is the address of a pthread_t value. It references the thread in other pthread_ family functions.

The second argument sets various thread attributes. This value is NULL most of the time.

The third argument is the name of the function to launch as another thread. This function’s declaration is important: It must use void arguments for flexibility. More on this topic in a few paragraphs.

The final argument consists of any arguments passed to the function, or NULL for none.

The function that runs the thread has this prototype:

void *(*start_routine)(void *)

This format identifies the function that’s launched into its own thread, running independently of the rest of the code.

To demonstrate a simple thread, the following code prompts for your name — easy peasy. But before doing so, it launches the thread_funct() function as a separate thread. This function outputs asterisks every second, annoying you as you type.

2022_05_28-Lesson.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);
    }

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

    return(0);
}

The main() function creates the new thread at Line 26. When an error occurs, the pthread_create() function returns a value other than zero. (It does not return -1 on error.) The global errno value is set, so the perror() function informs the user at Line 29 and the program stops. Otherwise, the user is prompted for input at Lines 33 and 34.

At the same time, the thread_funct() executes. It outputs an asterisk at Line 13. The newline ensures that the output buffer is flushed so that you see the asterisk, which interferes with your typing. The sleep() function at Line 14 pauses execution in the thread for one second before the for loop repeats and coughs up another asterisk.

Here is a sample run where I try typing my name as the program spits out asterisks:

What is your name? *
*
Dan*
G*
ook*
in*
*
Hello, Dan Gookin

The program (and its thread) stops after I type my name. If I wait, the thread outputs its eight asterisks and then stops:

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

In next week’s Lesson I continue exploration of multithreaded programming.

2 thoughts on “Here a Thread, There a Thread

  1. I am probably missing something but AFAIK, Windows does have C multithreading via the winapi. If you mean there is no POSIX threads for Windows, I think Mingw does support POSIX threads. Microsoft supports threads, but not the POSIX standard. With respect to Linux, C11 did add its own thread lib in addition to pthreads, but it depends on the compiler and it isn’t widely supported yet AFAIK. The best bet is to use POSIX for portability.

Leave a Reply