在多線程中,有一種叫線程本地存儲(Thread-Local Storage,TLS)的變量,它是每個線程有且只有一份自己的副本,對于這個線程來說,它是全局變量,可被所有函數共用;因為每個線程都有自己的一份內存來存儲這些變量,所以線程之間不會相互干擾。
TLS變量的內存分配和釋放是由操作系統自動管理的,程序員無需手動分配和釋放內存。同時,由于每個線程都有自己獨立的一份副本,因此TLS變量的讀寫不需要加鎖,可以提高多線程程序的性能。
Linux C語言程序中聲明這種類型的變量舉例如下:
static __thread int buf[max];
內存分配時機
- 線程啟動時: 當一個線程啟動時,為該線程分配的線程局部存儲 (TLS) 空間中會包含該線程的
static __thread
變量的內存空間。每個線程都有自己的 TLS 空間,因此每個線程的static __thread
變量都有自己的獨立副本。主線程的TLS變量是在main函數運行之前被分配,其它線程的TLS則是在線程被創建時分配。
When a program is started, the operating system creates a new process, and the C runtime library (CRT) initializes the program's memory. As part of this initialization, the CRT allocates memory for all
static
variables, includingstatic __thread
variables.When a new thread is created, the CRT allocates a new block of memory for the thread's stack, and initializes the
__thread
variables in that block.The
static
keyword ensures that the variable is initialized only once
- 首次訪問變量時: 如果在多線程環境中,某個線程首次訪問一個
static __thread
變量,則會在該線程的 TLS 空間中分配該變量的內存空間。此后,該線程后續對該變量的訪問都將使用該分配的內存空間。
內存分配的時機取決于以下因素
- 編譯器: 不同的編譯器可能會對
static __thread
變量的內存分配方式略有不同。例如,GNU Compiler Collection (GCC) 通常會在線程啟動時分配內存,而 Intel Compiler (ICC) 則可能在首次訪問變量時分配內存。 - 操作系統版本: 不同的操作系統版本可能對 TLS 的實現有所不同,這可能會影響
static __thread
變量的內存分配方式。
- 如果
static __thread
變量在聲明時被初始化,例如 static __thread int tls_var = 42; 那么它的內存將在程序啟動時被分配,并在程序結束時被釋放。如果static __thread
變量在聲明時沒有被初始化,那么它的內存將在第一次被訪問時被分配,并在線程結束時被釋放。例如:
static __thread int tls_var;void set_tls_var() { tls_var = 42; }
TLS 變量在內存中的位置和限制
- 通常是在棧上分配的,而不是在堆上分配的。這是因為 TLS 空間通常位于線程的棧中。
- 內存大小是固定的。
- 內存是線程私有的,但因為只要是內存就有地址,可以通過獲取TLS變量的地址實現線程外的訪問和操作。
- TLS變量的數量和總大小可能受到系統限制。
- 過多或過大的TLS變量可能會影響程序的性能和資源使用。
#include <stdio.h>
#include <pthread.h>static __thread int tls_var = 0; // TLS變量聲明void* thread_function(void* arg) {printf("Thread %ld: TLS var initial value = %d\n", (long)pthread_self(), tls_var);tls_var = 42; // 修改TLS變量printf("Thread %ld: TLS var new value = %d\n", (long)pthread_self(), tls_var);return NULL;
}int main() {pthread_t thread1, thread2;pthread_create(&thread1, NULL, thread_function, NULL);pthread_create(&thread2, NULL, thread_function, NULL);pthread_join(thread1, NULL);pthread_join(thread2, NULL);return 0;
}
作者寄語
以上如有錯漏之處,敬請大家指正。我是主修C/C++、Vue3,開發網站的程序員,我的聯系方式:
微信:TobeBuda
Email/Paypal: jinmin.si@outlook.com
邀請您加入「社區資訊服務」創業微信群,共同探討打造社區資訊服務的美好未來。
參考資料
gemini
mistral
claude
llama
chatgpt