什么是 POSIX Threads
????POSIX Threads (通常被縮寫為 Pthreads)是 POSIX (可移植操作系統(tǒng)接口怖糊,Portable Operating System Interface)的線程標準,定義了創(chuàng)建和操作線程的一套 API。
Pthreads
????實現(xiàn) POSIX 線程標準的庫常被稱作 Pthreads
, Pthreads
定義了一套 C 語言的類型、函數(shù)與常量,它以 pthread.h
頭文件和一個線程庫實現(xiàn)。
Pthreads API 中大致共有 100個 函數(shù)調(diào)用蚁鳖,全都以 pthread_
頭,并可以分為以下四類:
- 線程管理赁炎,例如創(chuàng)建線程醉箕,等待(join)線程,查詢線程狀態(tài)等甘邀。
- 互斥鎖(Mutex):創(chuàng)建琅攘、摧毀、鎖定松邪、解鎖坞琴、設置屬性等操作
- 條件變量(Condition Variable):創(chuàng)建、摧毀逗抑、等待剧辐、通知、設置與查詢屬性等操作
- 使用了互斥鎖的線程間的同步管理
數(shù)據(jù)類型
pthread_t
????pthread_t
是線程句柄邮府。出于可移植目的荧关,不能把它作為整數(shù)處理,應使用函數(shù) pthread_equal()
對兩個線程 id 進行比較褂傀。獲取自身所在線程 id 使用函數(shù)為 pthread_self()
忍啤。
pthread_attr_t
????pthread_attr_t
是線程屬性。主要包括 scope
屬性仙辟、detach
屬性同波、堆棧地址、堆棧大小叠国、優(yōu)先級未檩。主要屬性的意義如下:
-
__detachstate
,表示新線程是否與進程中其他線程脫離同步粟焊。- 設置為
PTHREAD_CREATE_DETACHED
冤狡, 則新線程不能用pthread_join()
來同步孙蒙,且在退出時自行釋放所占用的資源。 - 默認為
PTHREAD_CREATE_JOINABLE
悲雳】媛停可以在線程創(chuàng)建并運行以后用pthread_detach()
來設置 - 設置為
PTHREAD_CREATE_DETACHED
狀態(tài),不論是創(chuàng)建時設置還是運行時設置怜奖,則不能再恢復到PTHREAD_CREATE_JOINABLE
狀態(tài)浑测。
- 設置為
-
__schedpolicy
,表示新線程的調(diào)度策略歪玲,默認值為SCHED_OTHER
,后兩種調(diào)度策略僅對超級用戶有效掷匠,運行時可以用過pthread_setschedparam()
來改變-
SCHED_OTHER
滥崩,正常、非實時 -
SCHED_RR
讹语,實時钙皮、輪轉(zhuǎn)法 -
SCHED_FIFO
,實時顽决、先入先出
-
__schedparam
短条,一個struct sched_param
結(jié)構(gòu),目前僅有一個sched_priority
整型變量表示線程的運行優(yōu)先級才菠。這個參數(shù)僅當調(diào)度策略為實時(即SCHED_RR
或SCHED_FIFO
)時才有效茸时,并可以在運行時通過pthread_setschedparam()
函數(shù)來改變,默認為0赋访。系統(tǒng)支持的最大和最小的優(yōu)先級值可以用函數(shù)sched_get_priority_max
和sched_get_priority_min
得到可都。-
__inheritsched
,默認為PTHREAD_EXPLICIT_SCHED
蚓耽。-
PTHREAD_EXPLICIT_SCHED
表示新線程使用顯式指定調(diào)度策略和調(diào)度參數(shù)(即attr中的值)渠牲, -
PTHREAD_INHERIT_SCHED
而后者表示繼承調(diào)用者線程的值。
-
-
__scope
步悠,表示線程間競爭CPU的范圍签杈,也就是說線程優(yōu)先級的有效范圍。-
PTHREAD_SCOPE_SYSTEM
鼎兽,表示與系統(tǒng)中所有線程一起競爭CPU時間答姥, -
PTHREAD_SCOPE_PROCESS
后者表示僅與同進程中的線程競爭CPU。
-
pthread_barrier_t
????同步屏障數(shù)據(jù)類型
pthread_mutex_t
????pthread_mutex_t
是線程互斥鎖數(shù)據(jù)類型接奈,有兩種方法創(chuàng)建互斥鎖:
靜態(tài)方式
POSIX 定義了一個宏PTHREAD_MUTEX_INITIALIZER
來靜態(tài)初始化互斥鎖踢涌,-
動態(tài)方式
采用pthread_mutex_init()
函數(shù)來初始化互斥鎖,其中mutexattr
用于指定互斥鎖屬性序宦,如果為NULL
則使用默認屬性:int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t*mutexattr)
pthread_mutexattr_t
????互斥鎖的屬性 pthread_mutexattr_t
在創(chuàng)建鎖的時候指定睁壁,不同的鎖類型在試圖對一個已經(jīng)被鎖定的互斥鎖加鎖時表現(xiàn)不同。在 iOS 中有以下幾個類型可選:
-
PTHREAD_MUTEX_NORMAL
這是默認值,也就是普通鎖潘明。當一個線程加鎖以后行剂,其余請求鎖的線程將形成一個等待隊列,并在解鎖后按優(yōu)先級獲得鎖钳降。這種鎖策略保證了資源分配的公平性厚宰。 -
PTHREAD_MUTEX_ERRORCHECK
檢錯鎖,如果同一個線程請求同一個鎖遂填,則返回EDEADLK铲觉。 -
PTHREAD_MUTEX_RECURSIVE
嵌套鎖,允許同一個線程對同一個鎖成功獲得多次吓坚,并通過多次unlock
解鎖撵幽。如果是不同線程請求,則在加鎖線程解鎖時重新競爭礁击。
pthread_cond_t
???? pthread_cond_t
是條件變量數(shù)據(jù)類型盐杂,條件變量和互斥鎖一樣,都有靜態(tài)和動態(tài)兩種創(chuàng)建方式哆窿,
靜態(tài)方式
使用PTHREAD_COND_INITIALIZER
常量進行初始化動態(tài)方式
調(diào)用pthread_cond_init()
函數(shù)
操作線程函數(shù)
創(chuàng)建一個線程
int pthread_create(pthread_t _Nullable * _Nonnull __restrict,
const pthread_attr_t * _Nullable __restrict,
void * _Nullable (* _Nonnull)(void * _Nullable),
void * _Nullable __restrict);
終止當前線程
pthread_exit(void)
中斷一個線程
int pthread_cancel(pthread_t)
阻塞當前的線程
阻塞當前的線程链烈,直到另外一個線程運行結(jié)束
int pthread_join(pthread_t , void * _Nullable * _Nullable)
__DARWIN_ALIAS_C(pthread_join);
向指定ID的線程發(fā)送一個信號
????向指定ID的線程發(fā)送一個信號,如果線程不處理該信號挚躯,則按照信號默認的行為作用于整個進程强衡。信號值0為保留信號,作用是根據(jù)函數(shù)的返回值判斷線程是不是還活著秧均。
int pthread_kill(pthread_t threadId,int signal);
線程屬性函數(shù)
初始化線程屬性變量
int pthread_attr_init(pthread_attr_t *);
設置/獲取線程屬性變量的 detachstate
屬性
int pthread_attr_setdetachstate(pthread_attr_t *, int);
int pthread_attr_getdetachstate(const pthread_attr_t *, int *);
設置/獲取 scope
int pthread_attr_setscope(pthread_attr_t *, int);
int pthread_attr_getscope(const pthread_attr_t * __restrict, int * __restrict);
設置/獲取 schedparam
int pthread_attr_setschedparam(pthread_attr_t * __restrict,
const struct sched_param * __restrict);
int pthread_attr_getschedparam(const pthread_attr_t * __restrict,
struct sched_param * __restrict);
銷毀線程屬性
int pthread_attr_destroy(pthread_attr_t *);
互斥鎖函數(shù)
初始化互斥鎖
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t*mutexattr)
銷毀互斥鎖
int pthread_mutex_destroy(pthread_mutex_t *);
加鎖
int pthread_mutex_lock(pthread_mutex_t *);
int pthread_mutex_trylock(pthread_mutex_t *);
解鎖
int pthread_mutex_unlock(pthread_mutex_t *);
條件變量函數(shù)
初始化條件變量
int pthread_cond_init(
pthread_cond_t * __restrict,
const pthread_condattr_t * _Nullable __restrict)
__DARWIN_ALIAS(pthread_cond_init);
銷毀條件變量
int pthread_cond_destroy(pthread_cond_t *);
等待條件變量的特殊條件發(fā)生
????pthread_cond_wait()
必須與一個 pthread_mutex
配套使用食侮。該函數(shù)調(diào)用實際上依次做了3件事:
- 對當前
pthread_mutex
解鎖 - 把當前線程掛起到當前條件變量的線程隊列
- 被其它線程的信號喚醒后對當前
pthread_mutex
申請加鎖。
int pthread_cond_wait(pthread_cond_t * __restrict,
pthread_mutex_t * __restrict) __DARWIN_ALIAS_C(pthread_cond_wait);
發(fā)送一個信號
????pthread_cond_signal
發(fā)送一個信號給正在當前條件變量的線程隊列中處于阻塞等待狀態(tài)的線程目胡,使其脫離阻塞狀態(tài)锯七,喚醒后繼續(xù)執(zhí)行。如果沒有線程處在阻塞等待狀態(tài)誉己,pthread_cond_signal
也會成功返回眉尸。一般只給一個阻塞狀態(tài)的線程發(fā)信號。假如有多個線程正在阻塞等待當前條件變量巨双,則根據(jù)各等待線程優(yōu)先級的高低確定哪個線程接收到信號開始繼續(xù)執(zhí)行噪猾。如果各線程優(yōu)先級相同,則根據(jù)等待時間的長短來確定哪個線程獲得信號筑累。但 pthread_cond_signal
在多處理器上可能同時喚醒多個線程袱蜡,當只能讓一個被喚醒的線程處理某個任務時,其它被喚醒的線程就需要繼續(xù) wait
慢宗。
int pthread_cond_signal(pthread_cond_t *);
工具函數(shù)
查詢線程自身線程標識號
pthread_t pthread_self(void);
比較兩個線程標識
int pthread_equal(pthread_t _Nullable, pthread_t _Nullable);
執(zhí)行一次
某些需要僅執(zhí)行一次的函數(shù)坪蚁。其中第一個參數(shù)為 pthread_once_t
類型奔穿,是內(nèi)部實現(xiàn)的互斥鎖,保證在程序全局僅執(zhí)行一次敏晤。
int pthread_once(pthread_once_t *, void (* _Nonnull)(void));
線程私有存儲(Thread-local storage贱田,簡寫 tls)
Thread-local storage 是操作系統(tǒng)為線程單獨提供的私有空間,只有有限的容量嘴脾。通常通過 pthread
庫中的函數(shù)實現(xiàn):
創(chuàng)建 key
分配用于標識進程中線程特定數(shù)據(jù)的 pthread_key_t
類型的鍵
int pthread_key_create(pthread_key_t *, void (* _Nullable)(void *));
銷毀現(xiàn)有線程特定數(shù)據(jù) Key
int pthread_key_delete(pthread_key_t);
為指定線程的特定數(shù)據(jù)鍵設置綁定的值
extern int pthread_setspecific(unsigned long, const void*);
獲取綁定的值
extern void *pthread_getspecific(unsigned long);
objc tls 實現(xiàn)
typedef pthread_key_t tls_key_t;
static inline tls_key_t tls_create(void (*dtor)(void*)) {
tls_key_t k;
pthread_key_create(&k, dtor);
return k;
}
static inline void *tls_get(tls_key_t k) {
return pthread_getspecific(k);
}
static inline void tls_set(tls_key_t k, void *value) {
pthread_setspecific(k, value);
}