linux中的线程局部存储(TLS)实现线程间的同步和互斥pthread_key_create、pthread_setspecific、pthread_getspecific

目录

是什么

实现方式:

linux中声明线程局部存储变量

使用__thread关键字

使用pthread_key_t类型

线程的局部存储具有以下特点:

线程局部存储的限制

__thread:(使用简单,这里只给出例子)

线程特定键pthread_key_t

pthread_key_create函数

原型:

参数:

返回值:

destructor函数指针:

注意:

pthread_setspecific函数

原型:

参数:

返回值:

注意:

pthread_getspecific函数

原型:

参数:

返回值:

注意:

pthread_key_delete函数

原型:

参数:

返回值:

注意:

示例:

简单使用:

运行结果:

分析:

使用和传递析构函数:

运行结果:

分析:


是什么

线程的局部存储(Thread-Local Storage,TLS)是线程特定存储(Thread-Specific Storage,TSS)的更常用的名称,是一种内存区域,每个线程都可以存储自己的数据,使得不同的线程可以拥有不同的内存空间,相当于进程地址空间的全局变量区,只不过是线程私有的。线程局部存储在操作系统级别提供了一种方式,允许线程独立存储空间,为每个线程维护一份数据副本。这种特性在多线程编程中非常有用,因为它允许每个线程独立地存储自己的数据,避免了线程间的数据冲突和竞态条件。这使得编程更简单、更安全,并且减少了错误的可能性。

线程局部存储主要适用于需要高效处理大量并发线程的环境。它在很多高级语言中(如C++)也有实现,比如通过智能指针或者RAII(Resource Acquisition Is Initialization)来管理线程特定的数据。

实现方式:
  1. Thread Local Storage (TLS) API:操作系统提供了TLS的API,可以让程序员创建和管理每个线程的局部存储变量。这些API通常由操作系统库或线程库提供,并可以在程序中直接使用。

  2. 编程语言支持:一些编程语言提供了内置的机制来支持线程的局部存储。例如,在Java中,可以使用ThreadLocal类来创建线程本地变量,每个线程都有其自己的副本;在C++中,可以使用thread_local关键字来声明线程局部存储变量。

  3. 动态链接库:有些动态链接库(DLL)或共享对象(SO)提供了自己的TLS支持,可以让程序员将数据关联到线程中。这种方式通常需要使用库提供的特定函数来设置和获取线程局部存储的值。

linux中声明线程局部存储变量
使用__thread关键字

要声明一个线程局部存储变量,可以在变量声明前加上__thread关键字,例如:

__thread int my_variable;

这将声明一个线程局部存储的整数变量my_variable,每个线程都有自己的副本。在多线程环境中,不同线程可以访问和修改自己的副本,而不会影响其他线程的数据。

使用pthread_key_t类型

声明一个线程局部存储的整数变量tls_key

pthread_key_t tls_key;

线程的局部存储具有以下特点:
  1. 线程隔离:每个线程都有它自己的局部存储空间,可以在该空间中存储线程特定的数据,不同线程之间的数据互相隔离,避免了数据冲突和竞态条件。

  2. 数据共享:线程的局部存储允许不同线程之间共享代码,而不是对整个进程进行数据共享。这样可以减少线程间的通信开销,提高并发性能。他的作用类似于在普通进程中的全局变量,进程中的所有函数都可以直接调用这个变量而不用传参导致麻烦。

  3. 线程安全:线程的局部存储可以提供一种线程安全的方式来处理数据,每个线程都可以独立地修改和访问自己的局部存储变量,不会对其他线程造成影响。

线程局部存储的限制
  1. 由于每个线程都有自己的存储空间,因此如果线程之间需要共享数据,那么就需要额外的机制来同步访问。

  2. 线程局部存储的空间通常有限制,尤其是在资源受限的环境中。因此,在使用线程局部存储时,需要仔细考虑数据的大小和数量,以确保线程之间的数据不会造成过多的内存占用。不能对自定义的类进行局部存储。

  3. 由于线程局部存储是基于操作系统的特性,因此它可能会受到操作系统实现的影响。不同的操作系统可能会有不同的线程局部存储实现和限制。

__thread:(使用简单,这里只给出例子)
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
​
// 声明线程局部存储变量
__thread int tls_variable;
​
// 线程函数
void* thread_func(void* arg) {
    // 设置线程局部存储变量的值
    tls_variable = pthread_self();
    
    // 打印线程局部存储变量的值
    printf("Thread local variable: %ld\n", tls_variable);
      
    pthread_exit(NULL);
}
​
int main() {
    pthread_t thread1, thread2;
​
    pthread_create(&thread1, NULL, thread_func, NULL);
    pthread_create(&thread2, NULL, thread_func, NULL);
​
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
​
    return 0;
}

在这个例子中,我们声明了一个线程局部存储变量tls_variable,它在每个线程中都有自己的副本。在thread_func线程函数中,我们将线程的ID(通过pthread_self()函数获取)赋值给线程局部存储变量tls_variable。然后,在每个线程中打印该变量的值。

main函数中,我们创建了两个线程,并等待它们结束。每个线程在运行过程中都具有自己的线程局部存储变量,并且变量的值不会被其他线程所修改。

线程特定键pthread_key_t

pthread_key_t 是 POSIX 线程库(pthreads)的一部分,它提供了一种机制,使得每个线程都可以拥有自己的数据,而这些数据不会被其他线程访问。这种机制在多线程程序中非常有用,因为它可以避免全局变量的竞争条件,同时也无需在每个线程中复制数据。

/* Keys for thread-specific data */
typedef unsigned int pthread_key_t;

在 Linux 系统中,pthread_key_t 是一个无符号整数类型,通常在 <pthread.h> 头文件中。你可以使用 pthread_key_create() 函数来创建一个新的线程特定键,使用 pthread_key_delete() 函数来销毁一个线程特定键。

pthread_key_create函数

pthread_key_

pthread_create函数是用于创建一个新的线程的函数,它的返回值是一个整数类型的错误码。如果返回值为0,则表示线程创建成功;如果返回值为非零值,则表示线程创建失败,具体的错误码可以通过查阅相关文档来获取。在创建线程时,可以通过传递一个回调函数作为参数,该回调函数将在新线程中执行。回调函数的返回值类型为void指针,可以根据需要进行类型转换。在回调函数中,可以执行一些特定的操作,并返回一个值作为线程的返回值。在主线程中,可以使用pthread_join函数来等待新线程的结束,并获取其返回值。 以下是一个示例代码,演示了pthread_create函数的使用回调函数的返回值获取[^1]: ```c #include <stdio.h> #include <pthread.h> void *cb_fn(void *arg) //线程回调函数 { printf("in cb_fn\n"); return (void *)"OK"; } int main() { int ret; void *retval; pthread_t pid; ret = pthread_create(&pid, NULL, cb_fn, NULL); if (ret < 0) { printf("pthread_create error, ret=%d\n", ret); return -1; } pthread_join(pid, &retval); printf("retval = %s\n", (char *)retval); return 0; } ``` 在上述代码中,我们创建了一个新线程,并将cb_fn作为回调函数传递给pthread_create函数。在cb_fn函数中,我们打印了一条信息,并返回了一个字符串"OK"作为线程的返回值。在主线程中,我们使用pthread_join函数等待新线程的结束,并通过retval指针获取其返回值,并打印出来。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值