线程特定数据TSD,也称线程私有数据,每个线程对TSD的修改仅对自己可见。
POSIX中的TSD本质就是一个【索引:指针】键值对,如果我们要存放的数据很复杂,可将其存储在堆区,然后将其指针存储在TSD中;如果我们要存放的数据很简单,譬如一个整数或三两字符,可以直接存储在TSD上。
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
// 要存储的TSD结构
typedef struct _TSD
{
pthread_t tid; // 线程ID
char *tname; // 线程名
} TSD;
// TSD的键值
pthread_key_t key;
// 在进程范围内我们针对每个键只创建一次
pthread_once_t once_flag = PTHREAD_ONCE_INIT;
void destructor(void *ptr)
{
free(ptr);
}
void once(void)
{
// 创建一个键, 并记录在key中, 析构函数为destructor
// 线程在退出时, 会自动调用destructor去释放存储该TSD的内存
pthread_key_create(&key, destructor);
}
// 线程入口函数
void *test_tsd(void *arg)
{
TSD *tsd;
// 调用once进行初始化, 在进程范围内once只会被调用一次
pthread_once(&once_flag, once);
printf("%s start\n", (char *)arg);
// 创建键后其值初始化为空
if((tsd = (TSD *)pthread_getspecific(key)) == NULL)
{
// 分配内存存放TSD
tsd = malloc(sizeof(TSD));
tsd->tid = pthread_self();
tsd->tname = (char *)arg;
// 设置键值为TSD指针
pthread_setspecific(key, tsd);
printf("%s set tsd\n", (char *)arg);
}
// 获取键值并打印
tsd = (TSD *)pthread_getspecific(key);
printf("%s get tsd, tid: %x, name: %s\n", (char *)arg, tsd->tid, tsd->tname);
// 暂停2秒, 避免线程快速退出, 导致所有线程的运行过程呈串行, 无法验证TSD为线程私有数据
sleep(2);
// 再次获取键值并打印
tsd = (TSD *)pthread_getspecific(key);
printf("%s get tsd, tid: %x, name: %s\n", (char *)arg, tsd->tid, tsd->tname);
pthread_exit(NULL);
}
int main()
{
pthread_t tid1, tid2;
// 创建2个线程, 线程入口函数的参数为线程名指针
pthread_create(&tid1, NULL, test_tsd, (void *)"thread1");
pthread_create(&tid2, NULL, test_tsd, (void *)"thread2");
// 等待2个线程结束
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
}
编译后的运行结果如下:
thread2 start
thread2 set tsd
thread2 get tsd, tid: ff0c5700, name: thread2
thread1 start
thread1 set tsd
thread1 get tsd, tid: ff8c6700, name: thread1
thread2 get tsd, tid: ff0c5700, name: thread2
thread1 get tsd, tid: ff8c6700, name: thread1