Kiedy deklarujesz zmienną, thread_localkażdy wątek ma swoją własną kopię. Kiedy odnosisz się do niego po nazwie, używana jest kopia skojarzona z bieżącym wątkiem. na przykład
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;
}
Ten kod zwróci „2349”, „3249”, „4239”, „4329”, „2439” lub „3429”, ale nigdy więcej. Każdy wątek ma swoją własną kopię i, do której jest przypisywana, zwiększana, a następnie drukowana. Działający wątek mainma również swoją własną kopię, która jest przypisywana na początku, a następnie pozostawiana bez zmian. Kopie te są całkowicie niezależne i każda ma inny adres.
Jedynie nazwa jest pod tym względem wyjątkowa - jeśli bierzesz adres thread_localzmiennej, masz po prostu normalny wskaźnik do normalnego obiektu, który możesz swobodnie przekazywać między wątkami. na przykład
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;
}
Ponieważ adres ijest przekazywany do funkcji iwątku, można przypisać kopię przynależności do wątku głównego, mimo że tak jest thread_local. Ten program zwróci zatem „42”. Jeśli to zrobisz, musisz uważać, aby *pnie uzyskać dostępu po wyjściu wątku, do którego należy, w przeciwnym razie otrzymasz wiszący wskaźnik i niezdefiniowane zachowanie, tak jak w każdym innym przypadku, gdy wskazany obiekt zostanie zniszczony.
thread_localzmienne są inicjalizowane „przed pierwszym użyciem”, więc jeśli nigdy nie są dotykane przez dany wątek, to niekoniecznie są one nigdy inicjalizowane. Ma to pozwolić kompilatorom na uniknięcie konstruowania każdej thread_localzmiennej w programie dla wątku, który jest całkowicie niezależny i nie dotyka żadnego z nich. na przykład
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();
}
W tym programie są 2 wątki: wątek główny i wątek utworzony ręcznie. Żaden wątek nie jest wywoływany f, więc thread_localobiekt nigdy nie jest używany. W związku z tym nie jest określone, czy kompilator skonstruuje 0, 1 czy 2 wystąpienia my_class, a wyjściem może być „”, „hellohellogoodbyegoodbye” lub „hellogoodbye”.
strtok.strtokjest zepsuty nawet w środowisku jednowątkowym.