What is the _Thread_local keyword in C?

In this blog post, you will learn how to use the _Thread_local keyword in C. We will first describe what  _Thread_local is then how to create and use _Thread_local variable in your C programs.

 

 _Thread_local keyword in C:

_Thread_local is a storage-class specifier introduced in the C11. An object whose identifier is declared with  _Thread_local has thread storage duration. C has 4 storage duration, automatic, static dynamic, and thread.

Thread storage duration means storage for the variable is allocated when the thread begins and deallocated when the thread ends. Its lifetime is the entire execution of the thread for that it is created, and its stored value is initialized when the thread is started.

I believe you know that we can use only one storage at a time but _Thread_local is the only storage specifier that may appear with static or extern. You also must remember that if it is used on a block-scope declaration, it must be combined with either static or extern to decide linkage.

We generally use the keyword _Thread_local through the macro thread_local, defined in the header <threads.h>.

 

Example code:

As we have discussed that we can use _Thread_local with static and extern. In the below code we have used _Thread_local with static. So each thread has its own, distinct, object. It is the reason despite using the static storage specifier each thread prints the same result value.

#include <stdio.h>
#include "threads.h"

#define NUM_THREADS 5

int myThread(void *id)
{
    //_Thread_local variable
    static thread_local int var = 27;
    var += 6;

    //Print id of current thread and addr of var
    printf("Thread ID:[%d], Value of var: %d\n", *(int*)id, var);

    return 0;
}

int main()
{
    thrd_t id[NUM_THREADS];

    //thread ID arr
    int arr[NUM_THREADS] = {10, 11, 12, 13, 14};

    //Creating 5 threads
    for(int i = 0; i < NUM_THREADS; i++)
    {
        thrd_create(&id[i], myThread, &arr[i]);
    }

    //Wait for threads to complete
    for(int i = 0; i < NUM_THREADS; i++)
    {
        thrd_join(id[i], NULL);
    }

    return 0;
}

Output:

Thread ID:[10], Value of var: 33
Thread ID:[11], Value of var: 33
Thread ID:[13], Value of var: 33
Thread ID:[12], Value of var: 33
Thread ID:[14], Value of var: 33

 

If you will remove the thread_local from the above code you will get an unexpected result. See the below output, it will change on each run.

Thread ID:[10], Value of var: 33
Thread ID:[12], Value of var: 45
Thread ID:[11], Value of var: 39
Thread ID:[13], Value of var: 51
Thread ID:[14], Value of var: 57

 

Points to note about the thread_local specifier:

1.  It may be combined with static or extern.

2._Thread_local can not appear in the declaration specifiers of a function declaration.

3. You can specify it only on data items with static storage duration, which includes global data objects (both static and extern), local static objects.

4. If _Thread_local is used on a declaration of an object, it must be present on every declaration of the same object.

5. Each thread has its own, distinct, object. If the thread that executes the expression that accesses this object is not the thread that executed its initialization, the behavior is implementation-defined.

6. Array objects declared with the _Thread_local, static, or extern storage-class specifier cannot have a variable-length array (VLA) type.

 

Recommended Page for you: