Kapitel 16. Thread-lokale Daten

Durch das Schlüsselwort thread_local wird eine Thread-lokale Variable, auch unter dem Namen Thread-lokaler Speicher bekannt, definiert. Jeder Thread besitzt eine Kopie der Variablen, die an die Lebenszeit des Threads gebunden ist. Genau genommen ist es eine statische Variable, da sie dann initialisiert wird, wenn sie das erste Mal verwendet wird. Ihr Wert bleibt für die Lebenszeit des Threads erhalten.

threadLocal.cpp

01 #include <iostream>
02 #include <string>
03 #include <mutex>
04 #include <thread>
05
06 std::mutex coutMutex;
07
08 thread_local std::string s("hello from ");
09
10 void addThreadLocal(std::string const& s2){
11
12   s+=s2;
13   // protect std::cout
14   std::lock_guard<std::mutex> guard(coutMutex);
15   std::cout << s << std::endl;
16
17 }
18
19 int main(){
20
21   std::cout << std::endl;
22
23   std::thread t1(addThreadLocal,"t1"); // hello from t1
24   std::thread t2(addThreadLocal,"t2"); // hello from t2
25   std::thread t3(addThreadLocal,"t3"); // hello from t3
26   std::thread t4(addThreadLocal,"t4"); // hello from t4
27
28   t1.join();
29   t2.join();
30   t3.join();
31   t4.join();
32
33   std::cout << std::endl;
34
35 }
Listing 16.1 Thread-lokale Daten

In Listing 16.1 werden vier Threads erzeugt, die die Funktion addThreadLocal (Zeile 10) ausführen. Jeder Thread erhält eine Kopie der Variablen s (Zeile 8). Der Zugriff der neuen Threads auf std::cout wird durch std::lock_guard geschützt. Eine mögliche Ausgabe des Programms ist:

hello from t1
hello from t2
hello from t3
hello from t4
Listing 16.2 Ausgabe der Thread-lokalen Daten

Natürlich kann die Reihenfolge der Ausgabezeilen variieren.

Dynamische und statische Initialisierung

Thread-lokale Variablen können nicht nur zur Übersetzungszeit, sondern in C++11 auch zur Laufzeit initialisiert werden. So wird die Thread-lokale Variable s in Listing 16.1 durch den Ausdruck thread_local std::string s("hello from ") dynamisch (zur Laufzeit) initialisiert. Hingegen bewirkt thread_local int number=5, dass die Variable number statisch (zur Übersetzungszeit) initialisiert wird.

Praxistipp

Denken Sie über den Einsatz von Thread-lokalen Daten beim Portieren eines Single- auf ein Multithreaded-Programm nach.

Thread-lokaler Speicher bietet einen einfachen Migrationsweg für die Portierung eines Single-Threaded- auf ein Multithreaded-Programm an. Gemeinsam genutzte Variablen können im ersten Schritt als thread_local erklärt werden.

Aufgabe 16-1

Welche der Thread-lokalen Daten werden statisch bzw. dynamisch initialisiert?

constexpr int square(int x) { return x*x;}
int square2(int x){ return x*x;}

thread_local std::string s("hello from");
thread_local int number=5;
thread_local int2= square(3);
thread_local int3= square2(3);
thread_local static int buf[10];

Wie können Sie Ihre Ergebnisse verifizieren? Dies setzt natürlich die optimistische Annahme voraus, dass die aktuellen Compiler die C++11-Thread-lokalen Daten vollständig unterstützen.