在 C 语言多线程编程时,我们经常会在线程的执行过程中用到一些与本线程相关的数据,如果是比较简单的应用,我们可以为每个线程创建一个类似于执行环境的结构体,比如 struct thread_context,专门用来存储与本线程相关的数据,那么在函数调用的时候,我们就需要传递这个结构体指针,或者使用全局的结构体数组来保存每个线程的执行环境,但当某个函数需要使用该结构体时,还是需要一个类似于下标这种东西去索引对应的 struct thread_context,所以,常规的方法还是无法避免传递指针或下标。
好在,pthread 库提供了一系列接口用来存储和索引与线程相关的数据,具体来说,包括一个重要的数据类型:pthread_key_t,以及三个接口:
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
int pthread_setspecific(pthread_key_t key, const void *value);
void *pthread_getspecific(pthread_key_t key);
值得说明的是,在使用上述接口时,这个 pthread_key_t 类型的 key 应该定义成全局的,但不用担心,虽然该 key 对所有线程都可见,但通过 pthread_setspecific() 接口与该 key 绑定的变量是 per-thread 的。
上述三个接口简单明了,使用起来也很方便,主要包括以下几个步骤:
- 创建一个 key
- 设置与该 key 关联的数据
- 获取与该 key 关联的数据
下面看一个简单的使用示例:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#define THREAD_NUM 5
pthread_key_t key;
struct thread_vars {
int idx;
char name[16];
};
void thread_work(void)
{
struct thread_vars *data;
data = pthread_getspecific(key);
printf("I'm %s and idx is: %d\n", data->name, data->idx);
}
void *thread_func(void *args)
{
pthread_setspecific(key, args);
thread_work();
return NULL;
}
void do_test(void)
{
pthread_t tids[THREAD_NUM];
struct thread_vars *vars;
int i, ret;
void *val;
pthread_key_create(&key, NULL);
for (i = 0; i < THREAD_NUM; ++i) {
vars = (struct thread_vars *)malloc(sizeof(struct thread_vars));
vars->idx = i;
snprintf(vars->name, sizeof(vars->name), "Thread-%c", i + 'A');
ret = pthread_create(&tids[i], NULL, thread_func, (void *)vars);
}
for (i = 0; i < THREAD_NUM; ++i) {
pthread_join(tids[i], &val);
}
}
int main(void)
{
do_test();
return 0;
}
运行结果如下:
# gcc -o main ./main.c -lpthread
# ./main
I'm Thread-E and idx is: 4
I'm Thread-A and idx is: 0
I'm Thread-B and idx is: 1
I'm Thread-C and idx is: 2
I'm Thread-D and idx is: 3