一、什么是私有數據
應用程序設計中有必要提供一種變量,使得多個函數多個線程都可以訪問這個變量(看起來是個全局變量),但是線程對這個變量的訪問都不
會彼此產生影響(貌似不是全局變量哦),但是你需要這樣的數據,比如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;
}
华清图书馆
0元电子书,限时免费申领10本华清图书PDF版
扫码关注华清远见公众号