Ketika Anda mendeklarasikan variabel thread_local
maka setiap utas memiliki salinannya sendiri. Ketika Anda merujuknya dengan nama, maka salinan yang terkait dengan utas saat ini digunakan. misalnya
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;
}
Kode ini akan menampilkan "2349", "3249", "4239", "4329", "2439" atau "3429", tetapi tidak pernah lainnya. Setiap utas memiliki salinannya sendiri i
, yang ditugaskan untuk, bertambah dan kemudian dicetak. Utas yang berjalan main
juga memiliki salinannya sendiri, yang ditugaskan di awal dan kemudian dibiarkan tidak berubah. Salinan ini sepenuhnya independen, dan masing-masing memiliki alamat yang berbeda.
Hanya nama yang spesial dalam hal itu --- jika Anda mengambil alamat thread_local
variabel maka Anda hanya memiliki pointer normal ke objek normal, yang dapat Anda lewati dengan bebas di antara utas. misalnya
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;
}
Karena alamat i
dilewatkan ke fungsi utas, maka salinan i
milik utas utama dapat ditugaskan meskipun itu thread_local
. Dengan demikian program ini akan menghasilkan "42". Jika Anda melakukan ini, maka Anda harus berhati-hati agar *p
tidak diakses setelah utasnya keluar, jika tidak Anda mendapatkan pointer menggantung dan perilaku tidak terdefinisi seperti halnya kasus lain di mana objek yang diarahkan ke objek dihancurkan.
thread_local
variabel diinisialisasi "sebelum digunakan pertama kali", jadi jika mereka tidak pernah disentuh oleh utas yang diberikan maka mereka tidak selalu diinisialisasi. Ini untuk memungkinkan kompiler untuk menghindari membangun setiap thread_local
variabel dalam program untuk utas yang sepenuhnya mandiri dan tidak menyentuh salah satu dari mereka. misalnya
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();
}
Dalam program ini ada 2 utas: utas utama dan utas yang dibuat secara manual. Tidak ada utas panggilan f
, jadi thread_local
objek tidak pernah digunakan. Oleh karena itu tidak ditentukan apakah kompiler akan membuat contoh 0, 1 atau 2 my_class
, dan output mungkin "", "hellohellogoodbyegoodbye" atau "hellogoodbye".
strtok
.strtok
rusak bahkan dalam lingkungan berulir tunggal.