一、什么是私有数据
应用程序设计中有必要提供一种变量,使得多个函数多个线程都可以访问这个变量(看起来是个全局变量),但是线程对这个变量的访问都不
会彼此产生影响(貌似不是全局变量哦),但是你需要这样的数据,比如errno。那么这种数据就是线程的私有数据,尽管名字相同,但是每个
线程访问的都是数据的副本。
二、如何创建私有数据
1、在使用私有数据之前,你首先要创建一个与私有数据相关的键,要来获取对私有数据的访问权限 。这个键的类型是pthread_key_t
int pthread_key_create(pthread_key_t *key, void (*destructor)(voi8d*));
2、创建的键放在key指向的内存单元,destructor是与键相关的析构函数。当线程调用pthread_exit或者使用return返回,析构函数就会被调用。
当析构函数调用的时候,它只有一个参数,这个参数是与key关联的那个数据的地址(也就是你的私有数据啦),因此你可以在析构函数中将
这个数据销毁。
3、键使用完之后也可以销毁,当键销毁之后,与它关联的数据并没有销毁哦
int pthread_key_delete(pthread_key_t key);
三、如何使用私有数据
有了键之后,你就可以将私有数据和键关联起来,这样就就可以通过键来找到数据。所有的线程都可以访问这个键,但他们可以为键关联
不同的数据。(这岂不是一个名字一样,而值却不同的全局变量么)
1、int pthread_setspecific(pthread_key_t key, const void *value);
将私有数据与key关联
2、void *pthread_getspecific(pthread_key_t key);
获取私有数据的地址,如果没有数据与key关联,那么返回空
四、手册
PROLOG
This manual page is part of the POSIX Programmer’s Manual. The Linux implementation of this interface may
differ (consult the corresponding Linux manual page for details of Linux behavior), or the interface may
not be implemented on Linux.
//这只是POSIX的手册,Linux对这个接口的实现可能不一样,或者有的根本没有实现这个接口
NAME
pthread_key_create - thread-specific data key creation
//创建线程特殊数据
SYNOPSIS
#include <pthread.h>
//头文件
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
DESCRIPTION
The pthread_key_create() function shall create a thread-specific data key visible to all threads in the
process. Key values provided by pthread_key_create() are opaque objects used to locate thread-specific
data. Although the same key value may be used by different threads, the values bound to the key by
pthread_setspecific() are maintained on a per-thread basis and persist for the life of the calling thread.
//pthread_key_create()创造一个线程特殊的数据键,所有的线程都能使用它。key就是用来存放线程私有数据的
//尽管同一个key的名字被多个线程使用,但是每一个线程都通过pthread_setspecific()绑定自己的数据
Upon key creation, the value NULL shall be associated with the new key in all active threads. Upon thread
creation, the value NULL shall be associated with all defined keys in the new thread.
//刚创建key的时候,对于所有的线程来说,它的值都是空的。刚创建线程的时候,线程里所有的key都是空的
An optional destructor function may be associated with each key value. At thread exit, if a key value has
a non-NULL destructor pointer, and the thread has a non-NULL value associated with that key, the value of
the key is set to NULL, and then the function pointed to is called with the previously associated value as
its sole argument. The order of destructor calls is unspecified if more than one destructor exists for a
thread when it exits.
//每个key可以配置一个析构函数。当线程退出的时候,如果key的析构函数不为NULL,而且key也不是NULL,那么
//key会被置NULL,同时析构函数被调用。如果有多个析构函数,那么析构函数的调用顺序是不确定的
If, after all the destructors have been called for all non-NULL values with associated destructors, there
are still some non-NULL values with associated destructors, then the process is repeated. If, after at
least {PTHREAD_DESTRUCTOR_ITERATIONS} iterations of destructor calls for outstanding non-NULL values,
there are still some non-NULL values with associated destructors, implementations may stop calling
destructors, or they may continue calling destructors until no non-NULL values with associated destructors
exist, even though this might result in an infinite loop.
//如果所有的析构函数都被调用了,但是还有key的值不为空,那么进程会重复调用析构函数。如果至少有
//{PTHREAD_DESTRUCTOR_ITERATIONS次的析构函数被调用了,但是还有非空的key,那么实现者应该去结束
//析构函数,否则他们会一直调用,甚至可能陷入四循环
RETURN VALUE
If successful, the pthread_key_create() function shall store the newly created key value at *key and shall
return zero. Otherwise, an error number shall be returned to indicate the error.
//如果成功,会保存新的key,失败返回错误码
ERRORS
The pthread_key_create() function shall fail if:
//在以下情况会失败
EAGAIN The system lacked the necessary resources to create another thread-specific data key, or the sys-
tem-imposed limit on the total number of keys per process {PTHREAD_KEYS_MAX} has been exceeded.
//系统缺少必要的资源去创造key,或者key的数量已经达到了规定的大值
ENOMEM Insufficient memory exists to create the key.
//缺少内存
The pthread_key_create() function shall not return an error code of [EINTR].
//不会返回EINTR
PTHREAD_KEY_DELETE(3P) POSIX Programmer’s Manual PTHREAD_KEY_DELETE(3P)PROLOG
This manual page is part of the POSIX Programmer’s Manual. The Linux implementation of this interface may
differ (consult the corresponding Linux manual page for details of Linux behavior), or the interface may
not be implemented on Linux.
//这只是POSIX的手册,Linux对这个接口的实现可能不一样,或者有的根本没有实现这个接口
NAME
pthread_key_delete - thread-specific data key deletion
//删除key
SYNOPSIS
#include <pthread.h>
//头文件
int pthread_key_delete(pthread_key_t key);
DESCRIPTION
The pthread_key_delete() function shall delete a thread-specific data key previously returned by
pthread_key_create(). The thread-specific data values associated with key need not be NULL at the time
pthread_key_delete() is called. It is the responsibility of the application to free any application stor-
age or perform any cleanup actions for data structures related to the deleted key or associated thread-
specific data in any threads; this cleanup can be done either before or after pthread_key_delete() is
called. Any attempt to use key following the call to pthread_key_delete() results in undefined behavior.
//pthread_key_delete() 会删除key,当pthread_key_delete() 被调用的时候,key关联的值不必为空。当删除key
//的之后又必要去释放内存空间,做一些清理操作。这些清理操作可以在pthread_key_delete() 之前或之后调用
//任何试图在pthread_key_delete() 之后使用key的操作都是未知的
The pthread_key_delete() function shall be callable from within destructor functions. No destructor func-
tions shall be invoked by pthread_key_delete(). Any destructor function that may have been associated with
key shall no longer be called upon thread exit.
//pthread_key_delete()可以在析构函数中被调用,pthread_key_delete()不能调用析构函数。当线程退出时
//析构函数不能再被调用
RETURN VALUE
If successful, the pthread_key_delete() function shall return zero; otherwise, an error number shall be
returned to indicate the error.
//成功返回0,失败返回错误码
ERRORS
The pthread_key_delete() function may fail if:
//在以下情况会失败
EINVAL The key value is invalid.
//key的值是无效的
PTHREAD_GETSPECIFIC(3P) POSIX Programmer’s Manual PTHREAD_GETSPECIFIC(3P)
PROLOG
This manual page is part of the POSIX Programmer’s Manual. The Linux implementation of this interface may
differ (consult the corresponding Linux manual page for details of Linux behavior), or the interface may
not be implemented on Linux.
//这只是POSIX的手册,Linux对这个接口的实现可能不一样,或者有的根本没有实现这个接口
NAME
pthread_getspecific, pthread_setspecific - thread-specific data management
SYNOPSIS
#include <pthread.h>
//头文件
void *pthread_getspecific(pthread_key_t key);
int pthread_setspecific(pthread_key_t key, const void *value);
DESCRIPTION
The pthread_getspecific() function shall return the value currently bound to the specified key on behalf
of the calling thread.
//pthread_getspecific()返回当前线程绑定的key的值
The pthread_setspecific() function shall associate a thread-specific value with a key obtained via a pre-
vious call to pthread_key_create(). Different threads may bind different values to the same key. These
values are typically pointers to blocks of dynamically allocated memory that have been reserved for use by
the calling thread.
//pthread_setspecific()会绑定一个值到key,不同的线程可以绑定不同的值到相同的key,这些值都在当前线程
//的动态申请的内存里
The effect of calling pthread_getspecific() or pthread_setspecific() with a key value not obtained from
pthread_key_create() or after key has been deleted with pthread_key_delete() is undefined.
//当调用pthread_getspecific() or pthread_setspecific() 时的key不是经过pthread_key_create()创建的或者已经
//由 pthread_key_delete()删除了,那么结果是未知的
Both pthread_getspecific() and pthread_setspecific() may be called from a thread-specific data destructor
function. A call to pthread_getspecific() for the thread-specific data key being destroyed shall return
the value NULL, unless the value is changed (after the destructor starts) by a call to pthread_setspe-
cific(). Calling pthread_setspecific() from a thread-specific data destructor routine may result either in
lost storage (after at least PTHREAD_DESTRUCTOR_ITERATIONS attempts at destruction) or in an infinite
loop.
//析构函数可以调用pthread_getspecific() 和 pthread_setspecific() ,当pthread_getspecific()的时候如果key已经被
//销毁,那么获得的值是NULL,除非他由pthread_setspecific()改变了。在析构函数中调用 pthread_setspecific()可能
//导致内存泄露,或者死循环
Both functions may be implemented as macros.
//这两个函数可以由宏定义实现
RETURN VALUE
The pthread_getspecific() function shall return the thread-specific data value associated with the given
key. If no thread-specific data value is associated with key, then the value NULL shall be returned.
// pthread_getspecific()会返回一个key的值,如果没有值绑定到key,那么返回null
If successful, the pthread_setspecific() function shall return zero; otherwise, an error number shall be
returned to indicate the error.
//pthread_setspecific()如果成功返回0,失败返回错误码
ERRORS
No errors are returned from pthread_getspecific().
//pthread_getspecific()没有错误码
The pthread_setspecific() function shall fail if:
//pthread_setspecific()会因为以下情况失败
ENOMEM Insufficient memory exists to associate the value with the key.
//没有内存空间
The pthread_setspecific() function may fail if:
//pthread_setspecific()会因为以下情况失败
EINVAL The key value is invalid.
//key的值是无效的
These functions shall not return an error code of [EINTR].
//不会返回EINTR
五、实例
点击(此处)折叠或打开
/*DATE: 2015-4-17
*AUTHOR: WJ
*DESCRIPTION: 线程到私有数据, 一个像errno一样到数据
*/
#include "apue.h"
pthread_key_t key;
void *thread_fun1(void *arg)
{
printf("thread 1 start!\n");
int a = 1;
//将a和key关联
pthread_setspecific(key, (void *)a);
sleep(2);
printf("thread 1 key->data is %d\n", pthread_getspecific(key));
}
void *thread_fun2(void *arg)
{
sleep(1);
printf("thread 2 start!\n");
int a = 2;
//将a和key关联
pthread_setspecific(key, (void *)a);
printf("thread 2 key->data is %d\n", pthread_getspecific(key));
}
int main()
{
pthread_t tid1, tid2;
//创造一个key
pthread_key_create(&key, NULL);
//创造新线程
if(pthread_create(&tid1, NULL, thread_fun1, NULL))
{
printf("create new thread 1 failed\n");
return;
}
if(pthread_create(&tid2, NULL, thread_fun2, NULL))
{
printf("create new thread 2 failed\n");
return;
}
//等待新线程结束
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_key_delete(key);
return;
}