簡介
pthread - POSIX threads 踪央。
POSIX 是IEEE為在各種UNIX操作系統(tǒng)上運行軟件阎毅,而定義API的一系列互相關聯(lián)的標準的總稱来涨,其正式稱呼為IEEE Std 1003晒夹,而國際標準名稱為 ISO/IEC 9945 佳镜。
因此僚稿,對于 pthread, 有其標準蟀伸,也有其實現(xiàn)蚀同,實現(xiàn)相對于標準會存在一定的出入,這也體現(xiàn)在后文的介紹中啊掏。
POSIX.1 中的定義
POSIX.1 為 POSIX threads 或 Pthreads 的線程編程指定了一組接口(函數(shù)蠢络、頭文件)。 一個進程可以包含多個線程脖律,所有線程都在執(zhí)行同一個程序谢肾。 這些線程共享相同的全局內存(數(shù)據(jù)段和堆段),但每個線程都有自己的堆棧(自動變量)小泉。
POSIX.1 要求線程共享一系列其他屬性:
- parent process ID -
- process group ID and session ID
- controlling terminal
- user and group IDs
- open file descriptors
- record locks
- signal dispositions
- file mode creation mask
- current directory and root directory
- interval timers and POSIX timers
- nice value
- resource limits
- measurements of the consumption of CPU time and resources
除了 stack 之外芦疏,POSIX.1 還指定了以下屬性對于每個線程都是不同的、獨立的:
- thread ID ( 數(shù)據(jù)類型是:pthread_t)
- signal mask
- the errno variable
- alternate signal stack
- real-time scheduling policy and priority
下列的Linux特性也是每個線程獨有的:
- capabilities
- CPU affinity
POSIX Thread 的 Linux 實現(xiàn)
隨著時間的推移微姊,Linux 上的 GNU C 庫提供了兩個線程實現(xiàn) :
- LinuxThreads
- NPTL (Native POSIX Threads Library)
LinuxThreads
這是原始的 Pthreads 實現(xiàn)酸茴。 從 glibc2.4 開始,不再支持此實現(xiàn)兢交。
LinuxThreads 實現(xiàn)在許多方面偏離了 POSIX.1 規(guī)范薪捍,因此我們暫不討論 LinuxThreads,除非我們使用 的 glibc 是低于 2.4 的版本配喳。
NPTL
這是現(xiàn)代 Pthreads 實現(xiàn)酪穿。 與 LinuxThreads 相比,NPTL 更符合 POSIX.1 規(guī)范的要求晴裹,并且在創(chuàng)建大量線程時具有更好的性能被济。 NPTL 從 glibc 2.3.2 開始可用,并且需要 Linux 2.6 內核中存在的功能涧团。
在 NPTL 中:
- 一個進程中的所有線程都放在同一個線程組中只磷。
- 線程組的所有成員共享相同的 PID经磅。
- 不使用 manager thread。
NPTL 仍至少有一項不符合 POSIX.1:
- 線程不共享同一個 nice value
NPTL 一些不符合 POSIX.1 發(fā)生在較舊的內核:
- times(2) 和 getrusage(2) 返回的信息是每個線程的而不是進程范圍的(在內核 2.6.9 中修復)钮追。
- 線程不共享 resource limits(在內核 2.6.10 中修復)预厌。
- 線程不共享 interval timers(在內核 2.6.12 中修復)。
- 只允許主線程使用 setsid 啟動新 session (在內核 2.6.16 中修復)元媚。
- 只允許主線程使用 setpgid 使進程成為進程組 leader (在內核 2.6.16 中修復)轧叽。
- 線程具有不同的備用信號堆棧設置。 但是惠毁,新線程的備用信號堆棧設置是從創(chuàng)建它的線程復制的犹芹,因此線程最初共享備用信號堆棧(在內核 2.6.16 中修復)。
請注意以下有關 NPTL 實現(xiàn)的進一步要點:
- 如果 stack size soft resource limit 設置為 unlimited 以外的值鞠绰,則該值定義新線程的默認堆棧大小腰埂。 為了有效,這個限制必須在程序執(zhí)行之前設置蜈膨。
- 可以使用 ulimit -s (shell 內置命令)進行設置屿笼。
- 也可以在程序代碼中使用 setrlimit 設置 RLIMIT_STACK 的 大小。
pthread 編程
頭文件
#include <pthread.h>
pthread_t
typedef unsigned long int pthread_t;
- 用于聲明線程ID翁巍、標識線程
pthread_create
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg)
參數(shù):
- pthread_t :線程 ID
- pthread_attr_t :線程屬性
- start_routine :函數(shù)指針驴一,該函數(shù)的返回值類型為 void,該函數(shù)的參數(shù)類型為 void
- arg :將作為 start_routine 的參數(shù)
返回值:
- EAGAIN : 資源不足灶壶,遇到系統(tǒng)對資源施加的限制肝断,無法創(chuàng)建另一個線程。 有許多限制可能會觸發(fā)此錯誤:1. 已達到 RLIMIT_NPROC 軟資源限制(通過 setrlimit 設置驰凛,通過 getrlimit 進行查詢)胸懈,該限制限制了真實用戶 ID 的進程和線程數(shù); 2. 已達到內核對進程和線程數(shù)的系統(tǒng)范圍限制恰响,/proc/sys/kernel/threads-max趣钱; 3. 達到了 PID 的最大量,/proc/sys/kernel/pid_max胚宦;4. 其他資源:如 打開的最大文件描述符數(shù)量首有,vm.max_map_count 等。
- EINVAL : attr 中的設置無效枢劝。
- EPERM : 沒有權限設置attr 中指定的調度策略和參數(shù)井联。
注:在創(chuàng)建大量線程時,通常易發(fā)生 EAGAIN 錯誤
pthread_attr_t
typedef struct
{
int __detachstate; // 線程的分離狀態(tài)
int __schedpolicy; // 線程調度策略
struct sched_param __schedparam; // 線程的調度參數(shù)
int __inheritsched; // 線程的繼承性
int __scope; // 線程的作用域
size_t __guardsize; // 線程棧末尾的警戒緩沖區(qū)大小
int __stackaddr_set; // 線程的棧設置
void * __stackaddr; // 線程堆棧的位置
size_t __stacksize; // 線程棧的大小
}pthread_attr_t;
修改 pthread_attr_t 的接口:
pthread_attr_init
pthread_attr_destroy
pthread_attr_setaffinity_np(3)
pthread_attr_setdetachstate(3)
pthread_attr_setschedpolicy(3)
pthread_attr_setinheritsched(3)
pthread_attr_setschedparam(3)
pthread_attr_setscope(3)
pthread_attr_setguardsize(3)
pthread_attr_setstack(3)
pthread_attr_setstackaddr(3)
pthread_attr_setstacksize(3)
pthread_cancel
向線程發(fā)送取消請求
int pthread_cancel(pthread_t thread);
向線程發(fā)送取消請求您旁。
目標線程是否以及何時對取消請求做出反應取決于該線程控制下的兩個屬性:可取消性狀態(tài)(enabled (the default for new threads) or disabled)和可取消性類型(asynchronous or deferred (the default for new threads))烙常。
- 可取消性狀態(tài):如果線程 disable 取消,則取消請求將保持排隊狀態(tài)被冒,直到該線程 enable取消军掂。如果線程 enable 取消,則根據(jù)其可取消性類型確定何時發(fā)生取消昨悼。
- 可取消性類型:asynchronous 意味著線程可以在任何時刻被取消蝗锥。deferred 意味著取消將被延遲,直到線程下一次調用作為取消點的函數(shù)率触。
當一個取消請求被發(fā)起時, 線程中將會進入以下步驟:
彈出并調用取消性清理處理程序终议。
Thread-specific 的數(shù)據(jù)的析構函數(shù)將以 unspecified 的順序被調用。
線程終止葱蝗。
pthread_join
int pthread_join(pthread_t thread, void **retval);
pthread_join() 函數(shù)等待 thread 指定的線程終止穴张。 如果該線程已經終止,則 pthread_join() 立即返回两曼。 pthread_join() 指定的線程必須是 joinable 的皂甘。
如果 retval 不為 NULL,則 pthread_join() 將目標線程的退出狀態(tài)(即目標線程提供給 pthread_exit 的值)復制到 retval 指向的位置悼凑。 如果目標線程被取消偿枕,則 PTHREAD_CANCELED 被放置在 retval 指向的位置。
如果多個線程同時嘗試 join 同一個線程户辫,結果是不確定的渐夸。 如果調用 pthread_join() 的線程被取消,則目標線程將保持 joinable渔欢。
pthread_detach
int pthread_detach(pthread_t thread);
pthread_detach() 函數(shù)將線程標識的線程標記為已分離墓塌。 當一個分離的線程終止時,它的資源會自動釋放回系統(tǒng)奥额,而無需另一個線程 join 被終止的線程苫幢。
嘗試分離已分離的線程會導致未指定的行為。
返回值:
- EINVAL :thread 不是 joinable thread披坏。
- ESRCH :找不到線程ID所標識的線程态坦。
pthread_exit
void pthread_exit(void *retval);
終止調用線程。
pthread_exit() 函數(shù)終止調用線程并通過 retval 返回一個值(如果該線程可連接)棒拂,同一進程中的另一個線程可調用 pthread_join 獲取該返回值伞梯。
pthread_kill
#include <signal.h>
int pthread_kill(pthread_t thread, int sig);
向線程發(fā)送信號。
pthread_kill() 函數(shù)將信號 sig 發(fā)送到線程帚屉,該線程與調用者處于同一進程中谜诫。 信號異步定向到線程。如果 sig 為 0攻旦,則不發(fā)送信號喻旷,但仍會執(zhí)行錯誤檢查。
pthread_yield
int pthread_yield(void);
主動讓出執(zhí)行權,主動讓出CPU時間田轧。
pthread_self
pthread_t pthread_self(void);
獲取調用者的線程ID俏扩。
pthread_setaffinity_np
int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize,
const cpu_set_t *cpuset);
int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize,
cpu_set_t *cpuset);
pthread_setaffinity_np 設置線程和CPU的親和性珠叔。
pthread_getaffinity_np 獲取線程和CPU的親和性录豺。
cpu_set_t 的常用接口:
#include <sched.h>
void CPU_ZERO(cpu_set_t *set); // Clears set, so that it contains no CPUs.
void CPU_SET(int cpu, cpu_set_t *set); // Add CPU cpu to set.
void CPU_CLR(int cpu, cpu_set_t *set); // Remove CPU cpu from set.
int CPU_ISSET(int cpu, cpu_set_t *set); // Test to see if CPU cpu is a member of set.
int cpu 表示第 cpu 號 cpu紧卒,可以從 /proc/cpuinfo 中查看 cpu 號(processor)质蕉,通常是從 0 ~ N
更多接口見:CPU_SET
pthread_setname_np
int pthread_setname_np(pthread_t thread, const char *name);
int pthread_getname_np(pthread_t thread, char *name, size_t len);
pthread_setname_np 函數(shù)可用于為線程設置唯一名稱蔓同,這對于調試多線程應用程序非常有用涮拗。
pthread_getname_np 函數(shù)可用于獲取線程的名稱乾戏。
pthread_mutex_t
互斥量:用于控制對資源的訪問
int pthread_mutex_init(pthread_mutex_t *mutex,
const pthread_mutexattr_t *attr);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 等價于 pthread_mutex_init(&mutex, NULL);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
pthread_mutexattr_t
- pthread_mutexattr_setpshared - 設置互斥鎖范圍設置互斥鎖的強健屬性
- pthread_mutexattr_getpshared - 獲取互斥鎖范圍
- pthread_mutexattr_settype - 設置互斥鎖的類型屬性
- pthread_mutexattr_gettype - 獲取互斥鎖的類型屬性
- pthread_mutexattr_setprotocol - 設置互斥鎖屬性的協(xié)議
- pthread_mutexattr_getprotocol - 獲取互斥鎖屬性的協(xié)議
- pthread_mutexattr_setprioceiling - 設置互斥鎖屬性的優(yōu)先級上限
- pthread_mutexattr_getprioceiling - 獲取互斥鎖屬性的優(yōu)先級上限
- pthread_mutex_setprioceiling - 設置互斥鎖的優(yōu)先級上限
- pthread_mutex_getprioceiling - 獲取互斥鎖的優(yōu)先級上限
- pthread_mutexattr_setrobust_np - 設置互斥鎖的強健屬性
- pthread_mutexattr_getrobust_np - 獲取互斥鎖的強健屬性
pthread_mutexattr_settype
- PTHREAD_MUTEX_TIMED_NP:當一個線程加鎖后,其余請求鎖的線程形成等待隊列三热,在解鎖后按優(yōu)先級獲得鎖鼓择。 (默認值)
- PTHREAD_MUTEX_ADAPTIVE_NP:動作最簡單的鎖類型,解鎖后所有線程重新競爭就漾。
- PTHREAD_MUTEX_RECURSIVE_NP:允許同一線程對同一鎖成功獲得多次(遞歸鎖)呐能。當然也要解鎖多次。其余線程在解鎖時重新競爭抑堡。
- PTHREAD_MUTEX_ERRORCHECK_NP:若同一線程請求同一鎖催跪,返回EDEADLK(進行死鎖檢測,返回死鎖的錯誤夷野,避免死鎖)懊蒸,否則與PTHREAD_MUTEX_TIMED_NP動作相同(直接死鎖)。
pthread_cond_t
條件變量:用于線程間同步
int pthread_cond_init(pthread_cond_t *cond,
const pthread_condattr_t *attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; // 等價于 pthread_cond_init(&cond, NULL);
int pthread_cond_wait(pthread_cond_t *cond,
pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond,
pthread_mutex_t *mutex,
const struct timespec *abstime);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_destroy(pthread_cond_t *cond);
pthread_condattr_t
- pthread_condattr_setshared - 設置條件變量的進程共享屬性
- pthread_condattr_getshared - 獲取條件變量的進程共享屬性
- pthread_condattr_setclock - 此函數(shù)用于設置pthread_cond_timewait函數(shù)使用的時鐘ID
- pthread_condattr_getclock - 此函數(shù)獲取可被用于pthread_cond_timedwait函數(shù)的時鐘ID悯搔。