Коли ви оголошуєте змінну, thread_localто кожен потік має свою копію. Якщо ви посилаєтесь на нього по імені, тоді використовується копія, пов'язана з поточним потоком. напр
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;
}
Цей код виведе "2349", "3249", "4239", "4329", "2439" або "3429", але ніколи нічого іншого. Кожен потік має власну копію i, яка присвоюється, збільшується та друкується. Нитка, що працює, mainтакож має свою копію, яку призначають на початку, а потім залишають незмінною. Ці копії цілком незалежні, і кожна має різну адресу.
У цьому відношенні особливе лише ім'я --- якщо ви берете адресу thread_localзмінної, тоді у вас просто є звичайний вказівник на звичайний об'єкт, який ви можете вільно проходити між потоками. напр
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;
}
Оскільки адреса iпередається функції потоку, то копію iналежності до основного потоку можна присвоїти, навіть якщо вона є thread_local. Таким чином, ця програма виведе "42". Якщо ви це зробите, то вам потрібно подбати про те, щоб *pне отримати доступ після того, як нитка, до якої вона належить, вийшла, інакше ви отримаєте звисаючий вказівник та невизначену поведінку, як і будь-який інший випадок, коли об'єкт, що вказує на предмет, знищений.
thread_localзмінні ініціалізуються "до першого використання", тому, якщо вони ніколи не торкаються даної нитки, вони не обов'язково ніколи ініціалізуються. Це дозволить компіляторам уникати побудови кожної thread_localзмінної в програмі для потоку, який є повністю самостійним і не торкається жодної з них. напр
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();
}
У цій програмі є 2 потоки: головна нитка та створена вручну нитка. Жоден потік не викликає f, тому thread_localоб'єкт ніколи не використовується. Тому не визначено, чи буде компілятор побудувати 0, 1 або 2 екземпляри my_class, а вихід може бути "", "hellohellogoodbyegoodbye" або "hellogoodbye".
strtok.strtokруйнується навіть в одному різьбовому середовищі.