线程特有数据的具体实现,不是我们应该关心的。
但是了解它的实现,有助于我们理解它的使用方法。
一种典型的实现是:
- 进程维护一个全局的数组,存放线程特有数据的键信息。
- 每个线程包含一个数组,存储每个线程拥有的数据块的指针(通过
pthread_setspecific()
来存储指针)。
函数
1. pthread_key_create()
#include <pthread.h>
int pthread_key_create(pthread_key_t *key, void (*destructor)(void *));
//Return 0 on success, or a positive error number on error.
调用pthread_key_create()
会为线程特有数据创建一个新键,并通过参数key
来返回。
因为进程中所有线程都可(理论上,实际上不合适)使用返回的键,所以参数key
应指向一个全局变量。
线程终止时,如果与key
关联的值不为NULL,就会自动执行解构函数destructor
,并且将与key
关联的值作为解构函数的参数、
如果无需解构,可以将desturctor
设置为NULL。
同一个线程的多个解构函数的调用顺序不确定,因此解构函数应设计为相互独立。
2. pthread_setspecific() ,pthread_getspecific()
#include <pthread.h>
int pthread_setspecific(pthread_key_t key, const void*value);
Return 0 on success, or a positive error number on error.
void *pthread_getspecific(pthread_key_t key);
Return pointer, or NULL if no thread-specific data isassociated with key.
3. pthread_once()
#include <pthread.h>
int pthread_once(pthread_once_t *once_control, void (*init)(void));
Return 0 on success, or a positive error number on error.
多线程程序有时有这样的需求:不管创建来多少线程,有些初始化动作只能发生一次。
这个时候就可以使用pthread_once()
。
举个例子:
如果直接调用hello_world()
函数,那么会打印两个hello world
,但是通过pthread_once()
,就会值调用一次hello_world()
,只会打印一个hello world
。
#include <stdio.h>
#include <pthread.h>
pthread_once_t int_a = PTHREAD_ONCE_INIT;
void hello_world()
{
puts ("hello world");
}
void *func_1 (void *arg)
{
// pthread_once (&int_a, hello_world);
hello_world();
}
void *func_2 (void *arg)
{
// pthread_once (&int_a, hello_world);
hello_world();
}
int main (void)
{
pthread_t thread_1, thread_2;
pthread_create (&thread_1, NULL, func_1, NULL);
pthread_create (&thread_2, NULL, func_2, NULL);
pthread_join (thread_1, NULL);
pthread_join (thread_2, NULL);
}
4. pthread_key_delete()
销毁创建的pthread_key_t
。
#include <pthread.h>
int pthread_key_delete(pthread_key_t key);
示例
创建两个线程,分别给两个线程传入字符串"thread_1"、“thread_2”,这样就可以实现线程安全的函数。
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
pthread_key_t key_string;
pthread_once_t once_t_create_string = PTHREAD_ONCE_INIT;
void once_create_string()
{
pthread_key_create (&key_string, NULL);
}
void *func (void *arg)
{
pthread_once (&once_t_create_string, once_create_string);
char *string = pthread_getspecific (key_string);
if (string == NULL) {
string = strdup (arg);
pthread_setspecific (key_string, string);
}
puts (string);
}
int main (void)
{
pthread_t thread_1, thread_2;
pthread_create (&thread_1, NULL, func, "thread_1");
pthread_create (&thread_2, NULL, func, "thread_2");
pthread_join (thread_1, NULL);
pthread_join (thread_2, NULL);
pthread_key_delete (key_string);
}