多個函數共享數據時,除了經過函數間的返回值傳遞,還能夠使用全局變量。在多線程的環境下,全局變量會被各個線程共享,若是咱們須要只在單個線程所執行的函數間共享數據,例如要記錄每一個線程所執行過的函數名稱,該如何作呢?bash
能夠經過建立 線程私有數據(TSD: thread specific data) 來解決。在線程的內部該變量能夠被該線程的全部代碼訪問,每一個線程內的私有數據都是獨立的,不可被其餘線程訪問。TSD是一鍵多值的模式,既相同的key在不一樣線程對應不一樣的值。多線程
int pthread_key_create(pthread_key_t *, void (* _Nullable)(void *));
複製代碼
須要傳入兩個參數,第一個爲 pthread_key_t變量做爲key值,第二個是析構函數,用於在線程結束時釋放私有數據,內部配合free()函數使用。async
// 取值
void* _Nullable pthread_getspecific(pthread_key_t);
// 存值
int pthread_setspecific(pthread_key_t , const void * _Nullable);
複製代碼
當線程須要使用私有數據時,調用pthread_setspcific()傳入對應的key和值,調用pthread_getspecific()取出void* 變量再轉換成對應的類型。函數
int pthread_key_delete(pthread_key_t);
複製代碼
手動註銷key對應的私有數據,該函數並不會調用建立時的析構函數,而是將相關數據設爲NULL,並將變量釋放。ui
#import <UIKit/UIKit.h>
#include <stdio.h>
#include <pthread.h>
static pthread_key_t testPthreadKey;
void threadKeyClean(void *ptr)
{
if (ptr != NULL) {
free(ptr);
}
}
void testThread() {
pthread_key_create(&testPthreadKey, threadKeyClean);
}
struct test_data {
int i;
};
int main(int argc, char * argv[]) {
struct test_data *data = (struct test_data *)malloc(sizeof(struct test_data));
data->i = 1;
pthread_key_create(&testPthreadKey, threadKeyClean);
pthread_setspecific(testPthreadKey,&data);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
struct test_data *newData = (struct test_data *)malloc(sizeof(struct test_data));
newData->i = 100;
pthread_setspecific(testPthreadKey,&newData);
NSThread *thread = [NSThread currentThread];
NSLog(@"key=%ld, value=%d, thread=%@",testPthreadKey,newData->i, thread);
});
sleep(1);
NSThread *thread = [NSThread currentThread];
NSLog(@"key=%ld, value=%d, thread=%@",testPthreadKey,data->i, thread);
}
複製代碼
輸出結果爲 2020-02-26 11:17:44.690066+0800 TimeConsumeTool[442:162506] key=267, value=100, thread=<NSThread: 0x2830cca80>{number = 2, name = (null)}
2020-02-26 11:17:45.690508+0800 TimeConsumeTool[442:162480] key=267, value=1, thread=<NSThread: 0x283085a40>{number = 1, name = main}
可見主線程和子線程都各自維護了相同key的私有數據。spa
在iOS開發中,我本身在Hook Objc_msgSend時使用過TSD記錄每一個線程執行過的指令來計算時間開銷,另外在RxSwift的scheduler和也是使用TSD來存儲調度函數,在從此的開發中若是有相似的應用場景均可以使用TSD。線程