Коли ви оголошуєте змінну, 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
руйнується навіть в одному різьбовому середовищі.