Usa variabili thread_local in C

Jinku Hu 12 ottobre 2023
  1. Usa il tipo _Thread_local per dichiarare la variabile con la durata dell’archiviazione del thread
  2. Usa il tipo thread_local per dichiarare la variabile con la durata della memorizzazione dei thread
Usa variabili thread_local in C

Questo articolo spiegherà diversi metodi su come utilizzare le variabili thread_local in C.

Usa il tipo _Thread_local per dichiarare la variabile con la durata dell’archiviazione del thread

Il linguaggio C definisce più parole chiave per diverse classi di archiviazione come auto, static, register, extern. Dalla specifica dello standard C11, è stato aggiunto l’identificatore _Thread_local. La durata della memorizzazione di _Thread_local inizia al momento della creazione del thread e termina con la sua conclusione. Il valore memorizzato nell’oggetto _Thread_local viene inizializzato all’avvio del thread e ripulito quando il thread termina. In generale, gli oggetti locali del thread sono un’altra alternativa per evitare condizioni di competizione nelle risorse condivise. Vale a dire, separiamo implicitamente i dati tra i thread poiché gli oggetti qualificati _Thread_local hanno istanze separate per ogni 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);
}

Produzione:

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

Usa il tipo thread_local per dichiarare la variabile con la durata della memorizzazione dei thread

In alternativa, il linguaggio C definisce un’espressione macro thread_local per indicare lo specificatore come _Thread_local. Nota che le variabili thread_local dovrebbero essere dichiarate in un ambito di file per essere visibili a tutti i thread, oppure l’utente può aggiungere esplicitamente anche uno specificatore static per espandere il suo ambito a livello di file. La struttura del programma dovrà essere modificata poiché i thread dovrebbero comunicare i valori degli oggetti thread_local al thread principale. Il codice di esempio precedente che implementa il programma contatore semplice deve essere modificato per passare i valori del contatore incrementato al thread chiamante. Quindi, dobbiamo utilizzare la funzione thrd_join e il suo secondo argomento che memorizza il valore restituito dalla routine del thread. Tieni presente che tutti i valori incrementati dovrebbero essere sommati nel thread principale, che è anche responsabile della stampa del risultato finale nello 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);
}

Produzione:

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
Autore: 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

Articolo correlato - C Thread