How to Use thread_local Variables in C
-
Use the
_Thread_local
Type to Declare Variable With Thread Storage Duration -
Use the
thread_local
Type to Declare Variable With Thread Storage Duration
This article will explain several methods of how to use thread_local
variables in C.
Use the _Thread_local
Type to Declare Variable With Thread Storage Duration
The C language defines multiple keywords for different storage classes like auto
, static
, register
, extern
. Since the specification of the C11 standard, the _Thread_local
specifier was added. _Thread_local
storage duration starts at the moment of the thread creation and ends with its termination. The value stored in the _Thread_local
object is initialized when the thread is started and cleaned up when the thread terminates. In general, the thread-local objects are another alternative to avoid race conditions in shared resources. Namely, we implicitly separate the data between threads as _Thread_local
qualified objects have separate instances for each thread.
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <threads.h>
#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif
_Thread_local int counter = 0;
enum { MAX_ITER = 10000 };
void *incrementCounter(void *thr_id) {
long tid;
tid = (long)thr_id;
printf("thread %ld started incrementing ID - %lu\n", tid, thrd_current());
for (int i = 0; i < MAX_ITER; ++i) {
counter += 1;
}
return (void *)counter;
}
int main(int argc, char const *argv[]) {
thrd_t threads[NUM_THREADS];
int rc, sum = 0;
for (int i = 0; i < NUM_THREADS; ++i) {
rc = thrd_create(&threads[i], (thrd_start_t)incrementCounter, (void *)i);
if (rc == thrd_error) {
printf("ERORR; thrd_create() call failed\n");
exit(EXIT_FAILURE);
}
}
int retval;
for (int i = 0; i < NUM_THREADS; ++i) {
thrd_join(threads[i], &retval);
sum += retval;
}
printf("count = %d\n", sum);
thrd_exit(EXIT_SUCCESS);
}
Output:
thread 1 started incrementing ID - 140162648991488
thread 0 started incrementing ID - 140162657384192
thread 2 started incrementing ID - 140162640598784
thread 3 started incrementing ID - 140162632206080
count = 40000
Use the thread_local
Type to Declare Variable With Thread Storage Duration
Alternatively, the C language defines a macro expression thread_local
to denote the specifier as _Thread_local
. Note that thread_local
variables should be declared in a file scope to be visible to all threads, or the user may explicitly add a static
specifier as well to expand its scope to file level. The program structure will need to be modified as threads should communicate the values of thread_local
objects to the main thread. The previous example code that implements the simple counter program should be modified to pass the incremented counter values back to the calling thread. Thus, we need to utilize the thrd_join
function and its second argument that stores the thread routine’s return value. Mind that, all incremented values should be summed in the main thread, which is also responsible for printing out the final result to the stdout
.
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <threads.h>
#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif
thread_local int counter = 0;
enum { MAX_ITER = 10000 };
void *incrementCounter(void *thr_id) {
long tid;
tid = (long)thr_id;
printf("thread %ld started incrementing ID - %lu\n", tid, thrd_current());
for (int i = 0; i < MAX_ITER; ++i) {
counter += 1;
}
return (void *)counter;
}
int main(int argc, char const *argv[]) {
thrd_t threads[NUM_THREADS];
int rc, sum = 0;
for (int i = 0; i < NUM_THREADS; ++i) {
rc = thrd_create(&threads[i], (thrd_start_t)incrementCounter, (void *)i);
if (rc == thrd_error) {
printf("ERORR; thrd_create() call failed\n");
exit(EXIT_FAILURE);
}
}
int retval;
for (int i = 0; i < NUM_THREADS; ++i) {
thrd_join(threads[i], &retval);
sum += retval;
}
printf("count = %d\n", sum);
thrd_exit(EXIT_SUCCESS);
}
Output:
thread 1 started incrementing ID - 140162648991488
thread 2 started incrementing ID - 140162640598784
thread 0 started incrementing ID - 140162657384192
thread 3 started incrementing ID - 140162632206080
count = 40000
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook