Multithreading in C with threads.h

The C standard library offers multithreading via the header threads.h (C11). Atomic types, such as atomic_int, supporting atomic read and write operations are defined in the header stdatomic.h (C11).

The example program demonstrates the following tasks:

Alternatively, POSIX multithreading offered via the header pthread.h, which is not part of the C standard library, can be used.

Implementation Notes

Source Code

#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <threads.h>
#include <time.h>

#define NUM_THREADS     4
#define NUM_ITERATIONS  5

// Resource shared between the threads.
static atomic_int m_work;

// Thread worker function.  For simplicity, we pass the thread number directly
// as the pointer in the `tn` parameter.
static void *do_work(void *tn);

int main(void)
{
    thrd_t threads[NUM_THREADS];

    // Create threads.
    for (int t = 0; t < NUM_THREADS; t++)
    {
        if (
            thrd_create(
                &threads[t],
                (thrd_start_t)do_work,
                (void *)(long)t
            ) == thrd_error
        )
        {
            printf("Error creating thread #%d.\n", t);
            return EXIT_FAILURE;
        }
    }

    // Wait for all threads to finish.
    for (int t = 0; t < NUM_THREADS; t++)
        if (thrd_join(threads[t], NULL) == thrd_error)
            printf("Error joining thread #%d.\n", t);

    printf("All threads finished.\n");
    printf("Work result is %d.\n", m_work);
    return EXIT_SUCCESS;
}

static void *do_work(void *tn)
{
    int t = (int)(long)tn;
    printf("Thread #%d created (thread ID = %lu).\n", t, thrd_current());
    for (int i = 0; i < NUM_ITERATIONS; i++)
    {

        // Let thread sleep for 0 to 5 seconds to simulate work.  Actual sleep
        // may be shorter than the requested number of seconds, however, this
        // is irrelevant for this program.
        struct timespec requested_time = { .tv_sec = rand() % 5 };
        printf(
            "Thread #%d sleeping for %ld seconds.\n",
            t,
            requested_time.tv_sec
        );
        thrd_sleep(&requested_time, NULL);

        // Increment the resource shared between the threads by 1.
        int work = atomic_fetch_add(&m_work, 1);
        printf("Thread #%d incremented work to %d.\n", t, work);
    }
    printf("Thread #%d exiting successfully.\n", t);
    thrd_exit(EXIT_SUCCESS);
}