Wenn Sie eine Variable deklarieren, thread_local
hat jeder Thread eine eigene Kopie. Wenn Sie namentlich darauf verweisen, wird die dem aktuellen Thread zugeordnete Kopie verwendet. z.B
thread_local int i=0;
void f(int newval){
i=newval;
}
void g(){
std::cout<<i;
}
void threadfunc(int id){
f(id);
++i;
g();
}
int main(){
i=9;
std::thread t1(threadfunc,1);
std::thread t2(threadfunc,2);
std::thread t3(threadfunc,3);
t1.join();
t2.join();
t3.join();
std::cout<<i<<std::endl;
}
Dieser Code gibt "2349", "3249", "4239", "4329", "2439" oder "3429" aus, aber niemals etwas anderes. Jeder Thread hat eine eigene Kopie von i
, die zugewiesen, inkrementiert und dann gedruckt wird. Der laufende Thread main
hat auch eine eigene Kopie, die zu Beginn zugewiesen und dann unverändert gelassen wird. Diese Kopien sind völlig unabhängig und haben jeweils eine andere Adresse.
Diesbezüglich ist nur der Name besonders - wenn Sie die Adresse einer thread_local
Variablen verwenden, haben Sie nur einen normalen Zeiger auf ein normales Objekt, das Sie frei zwischen Threads übertragen können. z.B
thread_local int i=0;
void thread_func(int*p){
*p=42;
}
int main(){
i=9;
std::thread t(thread_func,&i);
t.join();
std::cout<<i<<std::endl;
}
Da die Adresse von i
an die Thread-Funktion übergeben wird, kann die Kopie der i
Zugehörigkeit zum Haupt-Thread zugewiesen werden, obwohl dies der Fall ist thread_local
. Dieses Programm gibt somit "42" aus. Wenn Sie dies tun, müssen Sie darauf achten, dass *p
nach dem Beenden des Threads, zu dem er gehört, nicht darauf zugegriffen wird. Andernfalls erhalten Sie einen baumelnden Zeiger und ein undefiniertes Verhalten, genau wie in jedem anderen Fall, in dem das Objekt, auf das verwiesen wird, zerstört wird.
thread_local
Variablen werden "vor der ersten Verwendung" initialisiert. Wenn sie also nie von einem bestimmten Thread berührt werden, werden sie nicht unbedingt jemals initialisiert. Auf diese Weise können Compiler vermeiden, dass jede thread_local
Variable im Programm für einen Thread erstellt wird, der vollständig in sich geschlossen ist und keinen von ihnen berührt. z.B
struct my_class{
my_class(){
std::cout<<"hello";
}
~my_class(){
std::cout<<"goodbye";
}
};
void f(){
thread_local my_class unused;
}
void do_nothing(){}
int main(){
std::thread t1(do_nothing);
t1.join();
}
In diesem Programm gibt es 2 Threads: den Haupt-Thread und den manuell erstellten Thread. Keiner der Threads wird aufgerufen f
, daher wird das thread_local
Objekt niemals verwendet. Es ist daher nicht spezifiziert, ob der Compiler 0, 1 oder 2 Instanzen von erstellt my_class
, und die Ausgabe kann "", "hellohellogoodbyegoodbye" oder "hellogoodbye" sein.
strtok
.strtok
ist sogar in einer einzelnen Thread-Umgebung defekt.