Utiliser des variables thread_local en C

Jinku Hu 12 octobre 2023
  1. Utilisez le type _Thread_local pour déclarer une variable avec la durée de stockage des threads
  2. Utilisez le type thread_local pour déclarer une variable avec la durée de stockage des threads
Utiliser des variables thread_local en C

Cet article explique plusieurs méthodes d’utilisation des variables thread_local en C.

Utilisez le type _Thread_local pour déclarer une variable avec la durée de stockage des threads

Le langage C définit plusieurs mots-clés pour différentes classes de stockage comme auto, static, register, extern. Depuis la spécification du standard C11, le spécificateur _Thread_local a été ajouté. La durée de stockage _Thread_local commence au moment de la création du thread et se termine à sa fin. La valeur stockée dans l’objet _Thread_local est initialisée au démarrage du thread et nettoyée à la fin du thread. En général, les objets thread-locaux sont une autre alternative pour éviter les conditions de concurrence dans les ressources partagées. A savoir, nous séparons implicitement les données entre les threads car les objets qualifiés _Thread_local ont des instances séparées pour chaque 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);
}

Production:

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

Utilisez le type thread_local pour déclarer une variable avec la durée de stockage des threads

Alternativement, le langage C définit une expression de macro thread_local pour désigner le spécificateur comme _Thread_local. Notez que les variables thread_local doivent être déclarées dans une portée de fichier pour être visibles par tous les threads, ou l’utilisateur peut également ajouter explicitement un spécificateur static pour étendre sa portée au niveau du fichier. La structure du programme devra être modifiée car les threads doivent communiquer les valeurs des objets thread_local au thread principal. L’exemple de code précédent qui implémente le programme de compteur simple doit être modifié pour renvoyer les valeurs de compteur incrémentées au thread appelant. Ainsi, nous devons utiliser la fonction thrd_join et son deuxième argument qui stocke la valeur de retour de la routine du thread. N’oubliez pas que toutes les valeurs incrémentées doivent être additionnées dans le thread principal, qui est également responsable de l’impression du résultat final dans le 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);
}

Production:

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
Auteur: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

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

Article connexe - C Thread