線程私有數據Thread-specific Data

概念

多個函數共享數據時,除了經過函數間的返回值傳遞,還能夠使用全局變量。在多線程的環境下,全局變量會被各個線程共享,若是咱們須要只在單個線程所執行的函數間共享數據,例如要記錄每一個線程所執行過的函數名稱,該如何作呢?bash

能夠經過建立 線程私有數據(TSD: thread specific data) 來解決。在線程的內部該變量能夠被該線程的全部代碼訪問,每一個線程內的私有數據都是獨立的,不可被其餘線程訪問。TSD是一鍵多值的模式,既相同的key在不一樣線程對應不一樣的值。多線程

API

建立

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。線程

相關文章
相關標籤/搜索