在多线程中,有一种叫线程本地存储(Thread-Local Storage,TLS)的变量,它是每个线程有且只有一份自己的副本,对于这个线程来说,它是全局变量,可被所有函数共用;因为每个线程都有自己的一份内存来存储这些变量,所以线程之间不会相互干扰,读写不需要加锁,可以提高多线程程序的性能。Linux C语言程序中声明这种类型的变量举例如下:
static __thread int buf[max];
内存分配时机
- 线程启动时: 当一个线程启动时,为该线程分配的线程局部存储 (TLS) 空间中会包含该线程的
static __thread
变量的内存空间,每个线程都有自己的 TLS 空间。主线程的TLS变量是在main函数运行之前被分配,其它线程的TLS则是通过pthread_create()函数创建线程时自动完成。
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 空间内存是线程私有的,但因为只要是内存就有地址,可以通过获取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
通义千问
文心一言