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 }
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
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.
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.