一、什么是私有數(shù)據(jù)
應用程序設計中有必要提供一種變量,使得多個函數(shù)多個線程都可以訪問這個變量(看起來是個全局變量),但是線程對這個變量的訪問都不
會彼此產(chǎn)生影響(貌似不是全局變量哦),但是你需要這樣的數(shù)據(jù),比如errno。那么這種數(shù)據(jù)就是線程的私有數(shù)據(jù),盡管名字相同,但是每個
線程訪問的都是數(shù)據(jù)的副本。
二、如何創(chuàng)建私有數(shù)據(jù)
1、在使用私有數(shù)據(jù)之前,你首先要創(chuàng)建一個與私有數(shù)據(jù)相關的鍵,要來獲取對私有數(shù)據(jù)的訪問權(quán)限 。這個鍵的類型是pthread_key_t
int pthread_key_create(pthread_key_t *key, void (*destructor)(voi8d*));
2、創(chuàng)建的鍵放在key指向的內(nèi)存單元,destructor是與鍵相關的析構(gòu)函數(shù)。當線程調(diào)用pthread_exit或者使用return返回,析構(gòu)函數(shù)就會被調(diào)用。
當析構(gòu)函數(shù)調(diào)用的時候,它只有一個參數(shù),這個參數(shù)是與key關聯(lián)的那個數(shù)據(jù)的地址(也就是你的私有數(shù)據(jù)啦),因此你可以在析構(gòu)函數(shù)中將
這個數(shù)據(jù)銷毀。
3、鍵使用完之后也可以銷毀,當鍵銷毀之后,與它關聯(lián)的數(shù)據(jù)并沒有銷毀哦
int pthread_key_delete(pthread_key_t key);
三、如何使用私有數(shù)據(jù)
有了鍵之后,你就可以將私有數(shù)據(jù)和鍵關聯(lián)起來,這樣就就可以通過鍵來找到數(shù)據(jù)。所有的線程都可以訪問這個鍵,但他們可以為鍵關聯(lián)
不同的數(shù)據(jù)。(這豈不是一個名字一樣,而值卻不同的全局變量么)
1、int pthread_setspecific(pthread_key_t key, const void *value);
將私有數(shù)據(jù)與key關聯(lián)
2、void *pthread_getspecific(pthread_key_t key);
獲取私有數(shù)據(jù)的地址,如果沒有數(shù)據(jù)與key關聯(lián),那么返回空
四、手冊
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對這個接口的實現(xiàn)可能不一樣,或者有的根本沒有實現(xiàn)這個接口
NAME
pthread_key_create - thread-specific data key creation
//創(chuàng)建線程特殊數(shù)據(jù)
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()創(chuàng)造一個線程特殊的數(shù)據(jù)鍵,所有的線程都能使用它。key就是用來存放線程私有數(shù)據(jù)的
//盡管同一個key的名字被多個線程使用,但是每一個線程都通過pthread_setspecific()綁定自己的數(shù)據(jù)
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.
//剛創(chuàng)建key的時候,對于所有的線程來說,它的值都是空的。剛創(chuàng)建線程的時候,線程里所有的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可以配置一個析構(gòu)函數(shù)。當線程退出的時候,如果key的析構(gòu)函數(shù)不為NULL,而且key也不是NULL,那么
//key會被置NULL,同時析構(gòu)函數(shù)被調(diào)用。如果有多個析構(gòu)函數(shù),那么析構(gòu)函數(shù)的調(diào)用順序是不確定的
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.
//如果所有的析構(gòu)函數(shù)都被調(diào)用了,但是還有key的值不為空,那么進程會重復調(diào)用析構(gòu)函數(shù)。如果至少有
//{PTHREAD_DESTRUCTOR_ITERATIONS次的析構(gòu)函數(shù)被調(diào)用了,但是還有非空的key,那么實現(xiàn)者應該去結(jié)束
//析構(gòu)函數(shù),否則他們會一直調(diào)用,甚至可能陷入四循環(huán)
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.
//系統(tǒng)缺少必要的資源去創(chuàng)造key,或者key的數(shù)量已經(jīng)達到了規(guī)定的大值
ENOMEM Insufficient memory exists to create the key.
//缺少內(nèi)存
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對這個接口的實現(xiàn)可能不一樣,或者有的根本沒有實現(xiàn)這個接口
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() 被調(diào)用的時候,key關聯(lián)的值不必為空。當刪除key
//的之后又必要去釋放內(nèi)存空間,做一些清理操作。這些清理操作可以在pthread_key_delete() 之前或之后調(diào)用
//任何試圖在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()可以在析構(gòu)函數(shù)中被調(diào)用,pthread_key_delete()不能調(diào)用析構(gòu)函數(shù)。當線程退出時
//析構(gòu)函數(shù)不能再被調(diào)用
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對這個接口的實現(xiàn)可能不一樣,或者有的根本沒有實現(xiàn)這個接口
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,這些值都在當前線程
//的動態(tài)申請的內(nèi)存里
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.
//當調(diào)用pthread_getspecific() or pthread_setspecific() 時的key不是經(jīng)過pthread_key_create()創(chuàng)建的或者已經(jīng)
//由 pthread_key_delete()刪除了,那么結(jié)果是未知的
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.
//析構(gòu)函數(shù)可以調(diào)用pthread_getspecific() 和 pthread_setspecific() ,當pthread_getspecific()的時候如果key已經(jīng)被
//銷毀,那么獲得的值是NULL,除非他由pthread_setspecific()改變了。在析構(gòu)函數(shù)中調(diào)用 pthread_setspecific()可能
//導致內(nèi)存泄露,或者死循環(huán)
Both functions may be implemented as macros.
//這兩個函數(shù)可以由宏定義實現(xiàn)
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.
//沒有內(nèi)存空間
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: 線程到私有數(shù)據(jù), 一個像errno一樣到數(shù)據(jù)
*/
#include "apue.h"
pthread_key_t key;
void *thread_fun1(void *arg)
{
printf("thread 1 start!\n");
int a = 1;
//將a和key關聯(lián)
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關聯(lián)
pthread_setspecific(key, (void *)a);
printf("thread 2 key->data is %d\n", pthread_getspecific(key));
}
int main()
{
pthread_t tid1, tid2;
//創(chuàng)造一個key
pthread_key_create(&key, NULL);
//創(chuàng)造新線程
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;
}
//等待新線程結(jié)束
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_key_delete(key);
return;
}