Linux C语言程序中线程本地存储变量的内存分配和使用

在多线程中,有一种叫线程本地存储(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, including static __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

通义千问

文心一言

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qiuzen

您的资助将帮助我创作更好的作品

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值