C/C++ 執行緒本地儲存
阿新 • • 發佈:2021-07-13
Thread Local Storage
我們知道多執行緒共享同一個程序的地址空間,對全域性變數來說,某一個執行緒對其修改會影響其他所有執行緒。
如果我們需要一個變數在每個執行緒中都能訪問,並且值在每個執行緒中互不影響,這就是 Thread Local Storage(TLS,也稱 “執行緒私有資料”)。
Linux下支援兩種方式定義和使用TLS變數,具體如下表:
定義方式 | 支援層次 | 訪問方式 |
__thread 關鍵字 | 語言層面 | 與全域性變數完全一樣 |
pthread_key_create() 函式 | 執行庫層面 |
pthread_get_specific(),讀 pthread_set_specific(),寫 |
__thread 關鍵字
看個例子,全域性變數 var 被定義為 執行緒私有變數
#include <stdio.h> #include <stdint.h> #include <pthread.h> __thread int var = 0; // var定義為執行緒變數,每個數線擁有一份 void* worker(void* arg) { for (int i = 0; i < 1e4; i++) { var++; } printf("child thread [%lu] var(%p)=%d\n", pthread_self(), &var, var); return 0; } int main(){ pthread_t pid1, pid2; printf("var=%d\n", var); pthread_create(&pid1, NULL, worker, (void *)0); pthread_create(&pid2, NULL, worker, (void *)1); pthread_join(pid1, NULL); pthread_join(pid2, NULL); printf("main thread [%lu] var(%p)=%d\n", pthread_self(), &var, var); return 0; }
執行結果
var=0 child thread [139770628466432] var(0x7f1ee2a8e6fc)=10000 child thread [139770620073728] var(0x7f1ee228d6fc)=10000 main thread [139770645350272] var(0x7f1ee3aa877c)=0
可見,主執行緒和兩個子執行緒訪問到的 var 變數地址不一樣,每個執行緒對 var 都有一份自己的拷貝,不會互相影響。
pthread_key_create() 函式
也看個例子,
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <pthread.h> struct foo { int var; }; void* worker(void* arg) { pthread_key_t* key = (pthread_key_t*) arg; foo* ptr; if ((ptr = (foo*)pthread_getspecific(*key)) == NULL) { ptr = (foo*) malloc(sizeof(foo)); (void) pthread_setspecific(*key, ptr); } for (int i = 0; i < 1e4; i++) { ptr->var++; } printf("child thread [%lu] var(%p)=%d\n", pthread_self(), &(ptr->var), ptr->var); return 0; } int main(){ pthread_key_t key; (void) pthread_key_create(&key, NULL); pthread_t pid1, pid2; pthread_create(&pid1, NULL, worker, (void *)(&key)); pthread_create(&pid2, NULL, worker, (void *)(&key)); pthread_join(pid1, NULL); pthread_join(pid2, NULL); foo* ptr; if ((ptr = (foo*)pthread_getspecific(key)) == NULL) { printf("main thread [%lu] var null\n"); } else { printf("main thread [%lu] var(%p)=%d\n", pthread_self(), &(ptr->var), ptr->var); } pthread_key_delete(key); return 0; }
執行結果
child thread [140470755546880] var(0x7fc1e00008c0)=10000 child thread [140470747154176] var(0x7fc1d80008c0)=10000 main thread [140470770246240] var null
不同執行緒通過同一個key,訪問到不同的value,可以想象 Linux 的實現會是一個map,每個執行緒對應不同的value。
======專注高效能web伺服器架構和開發=====