Verwendung von thread_local-Variablen in C
-
Verwenden Sie den Typ
_Thread_local
, um eine Variable mit Thread-Speicherdauer zu deklarieren -
Verwenden Sie den Typ
thread_local
, um eine Variable mit Thread-Speicherdauer zu deklarieren
In diesem Artikel werden verschiedene Methoden zur Verwendung von thread_local
-Variablen in C erläutert.
Verwenden Sie den Typ _Thread_local
, um eine Variable mit Thread-Speicherdauer zu deklarieren
Die Sprache C definiert mehrere Schlüsselwörter für verschiedene Speicherklassen wie auto
, static
, register
, extern
. Seit der Spezifikation des C11-Standards wurde der Spezifizierer _Thread_local
hinzugefügt. Die Speicherdauer _Thread_local
beginnt zum Zeitpunkt der Thread-Erstellung und endet mit deren Beendigung. Der im Objekt _Thread_local
gespeicherte Wert wird beim Starten des Threads initialisiert und beim Beenden des Threads bereinigt. Im Allgemeinen sind die threadlokalen Objekte eine weitere Alternative, um Race-Bedingungen in gemeinsam genutzten Ressourcen zu vermeiden. Wir trennen die Daten implizit zwischen Threads, da qualifizierte Objekte mit dem Namen _Thread_local
für jeden Thread separate Instanzen haben.
#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);
}
Ausgabe:
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
Verwenden Sie den Typ thread_local
, um eine Variable mit Thread-Speicherdauer zu deklarieren
Alternativ definiert die C-Sprache einen Makroausdruck thread_local
, um den Bezeichner als _Thread_local
zu bezeichnen. Beachten Sie, dass thread_local
-Variablen in einem Dateibereich deklariert werden sollten, damit sie für alle Threads sichtbar sind. Andernfalls kann der Benutzer auch explizit einen static
Bezeichner hinzufügen, um seinen Bereich auf Dateiebene zu erweitern. Die Programmstruktur muss geändert werden, da Threads die Werte von thread_local
-Objekten an den Hauptthread übermitteln sollen. Der vorherige Beispielcode, der das einfache Zählerprogramm implementiert, sollte geändert werden, um die inkrementierten Zählerwerte an den aufrufenden Thread zurückzugeben. Daher müssen wir die Funktion thrd_join
und ihr zweites Argument verwenden, das den Rückgabewert der Thread-Routine speichert. Beachten Sie, dass alle inkrementierten Werte im Hauptthread summiert werden sollten, der auch für den Ausdruck des Endergebnisses im stdout
verantwortlich ist.
#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);
}
Ausgabe:
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